﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область СлужебныйПрограммныйИнтерфейс

////////////////////////////////////////////////////////////////////////////////
// Обработчики событий подсистем конфигурации.

 // Параметры:
//   ФормаОтчета - ФормаКлиентскогоПриложения:
//    * ОтчетТабличныйДокумент - ТабличныйДокумент
//   Команда - КомандаФормы
//   Результат - Булево
// 
Процедура ПриОбработкеКоманды(ФормаОтчета, Команда, Результат) Экспорт
	
	Если ФормаОтчета.НастройкиОтчета.ПолноеИмя = "Отчет.ПродлениеСрокаДействияЭлектронныхПодписей" Тогда
		
		ПараметрыФормы = Новый Структура("РежимПродления", ФормаОтчета.КлючТекущегоВарианта);
		ОткрытьФорму("ОбщаяФорма.ПродлениеСрокаДействияЭлектронныхПодписей", ПараметрыФормы, ФормаОтчета, ФормаОтчета.КлючУникальности);
		
	КонецЕсли;
	
КонецПроцедуры

// Выполняет получение установленных криптопровайдеров.
//  
// Параметры:
//  Оповещение - ОписаниеОповещения - оповещение о результате выполнения, один из типов:
//    = Неопределено - данные не получены (не установлено расширение для работы с криптографией или компонента)
//    = Структура:
//      # ПроверкаВыполнена = Булево - Истина, если проверка выполнена, получены установленные криптопровайдеры.
//        если Ложь, то будет заполнена Ошибка.
//      # Ошибка = Строка - текст ошибки
//      # Криптопровайдеры          = Массив из ЭлектроннаяПодписьСлужебныйКлиентСервер.НовоеРасширенноеОписаниеПрограммы
//      # КриптопровайдерыНаСервере = Массив из ЭлектроннаяПодписьСлужебныйКлиентСервер.НовоеРасширенноеОписаниеПрограммы
//  ПараметрыПроверки - Неопределено
//                    - Структура:
//                         * УстанавливатьРасширение - Булево - устанавливать расширение для работы с электронной подписью.
//                         * УстанавливатьКомпоненту - Булево - устанавливать компоненту для работы с электронной подписью.
//                         * ПроверятьНаСервере      - Булево - получить список криптопровайдеров на сервере.
// 
Процедура ПолучитьУстановленныеКриптопровайдеры(Оповещение, ПараметрыПроверки = Неопределено) Экспорт

	Контекст = Новый Структура;
	Контекст.Вставить("УстанавливатьРасширение", Истина);
	Контекст.Вставить("УстанавливатьКомпоненту", Истина);
	Контекст.Вставить("Результат", РезультатПолученияУстановленныхКриптопровайдеров());
	
	ПроверятьНаСервере = Неопределено;
	
	Если ТипЗнч(ПараметрыПроверки) = Тип("Структура") Тогда
		ЗаполнитьЗначенияСвойств(Контекст, ПараметрыПроверки);
		ПроверятьНаСервере = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыПроверки, "ПроверятьНаСервере", Неопределено);
	КонецЕсли;
	
	Если ПроверятьНаСервере = Неопределено Тогда
		ПроверятьНаСервере = ЭлектроннаяПодписьКлиент.ПроверятьЭлектронныеПодписиНаСервере()
		Или ЭлектроннаяПодписьКлиент.СоздаватьЭлектронныеПодписиНаСервере();
	КонецЕсли;
	
	Если ПроверятьНаСервере Тогда
		РезультатНаСервере = ЭлектроннаяПодписьСлужебныйВызовСервера.УстановленныеКриптопровайдеры();
		Если РезультатНаСервере.ПроверкаВыполнена Тогда
			Контекст.Результат.КриптопровайдерыНаСервере = РезультатНаСервере.Криптопровайдеры;
		КонецЕсли;
	КонецЕсли;

	Контекст.Вставить("Оповещение", Оповещение);
	Контекст.Вставить("ПродолжатьБезУстановкиРасширения", Истина);
	
	ОповещениеОПродолжении = Новый ОписаниеОповещения("ПолучитьУстановленныеКриптопровайдерыПослеПодключенияКомпоненты",
		ЭтотОбъект, Контекст);
	ВыполнитьПослеПроверкиРасширенияИКомпоненты(ОповещениеОПродолжении, Контекст);
	
КонецПроцедуры

// Получает из сертификата адреса списков отзыва, скачивает, устанавливает в промежуточное хранилище сертификатов
// 
// Параметры:
//  ПараметрыУстановкиСпискаОтзыва - см. ПараметрыУстановкиСпискаОтзыва
//
Процедура УстановитьСписокОтзываСертификата(ПараметрыУстановкиСпискаОтзыва) Экспорт
	
	Оповещение = Новый ОписаниеОповещения("УстановитьСписокОтзываСертификатаПослеПодключенияКомпоненты",
			ЭтотОбъект, ПараметрыУстановкиСпискаОтзыва);
	
	Параметры = Новый Структура;
	
	Если ЗначениеЗаполнено(ПараметрыУстановкиСпискаОтзыва.ТекстПояснения) Тогда
		Параметры.Вставить("ТекстПояснения", ПараметрыУстановкиСпискаОтзыва.ТекстПояснения);
	КонецЕсли;
	
	ВыполнитьПослеПроверкиРасширенияИКомпоненты(Оповещение, Параметры);
	
КонецПроцедуры

// Параметры установки списка отзыва.
// 
// Параметры:
//  Сертификат - ДвоичныеДанные
//             - Строка - адрес во временном хранилище.
//             - Строка - строковое представление сертификата в формате Base64.
//             - СертификатКриптографии
// 
// Возвращаемое значение:
//  Структура:
//   * Сертификат - ДвоичныеДанные
//             - Строка - адрес во временном хранилище.
//             - Строка - строковое представление сертификата в формате Base64.
//             - СертификатКриптографии
//   * Адреса  - Строка - адрес списка отзыва, если не указан, загрузка будет с адресов, указанных в сертификате.
//             - Массив из Строка
//   * АдресВнутренний - Строка - если указан, список отзыва будет записан в кэш.
//   * ОповещениеОЗавершении - Неопределено
//                           - ОписаниеОповещения - оповещение, которое вызывается после установки c результатом:
//                              # Структура:
//                                ## УстановкаВыполнена - Булево
//                                ## Сообщение - сообщение о результате установки
//   * Форма - ФормаКлиентскогоПриложения - владелец формы установки
//   * ТекстПояснения - Строка - текст пояснения для установки компоненты.
//
Функция ПараметрыУстановкиСпискаОтзыва(Сертификат) Экспорт
	
	ПараметрыУстановкиСпискаОтзыва = Новый Структура;
	ПараметрыУстановкиСпискаОтзыва.Вставить("Сертификат", Сертификат);
	ПараметрыУстановкиСпискаОтзыва.Вставить("Адреса", Новый Массив);
	ПараметрыУстановкиСпискаОтзыва.Вставить("АдресВнутренний");
	ПараметрыУстановкиСпискаОтзыва.Вставить("ОповещениеОЗавершении");
	ПараметрыУстановкиСпискаОтзыва.Вставить("Форма");
	ПараметрыУстановкиСпискаОтзыва.Вставить("ТекстПояснения");
	
	Возврат ПараметрыУстановкиСпискаОтзыва;
	
КонецФункции

// Установить сертификат
// 
// Параметры:
//  ПараметрыУстановкиСертификата - см. ПараметрыУстановкиСертификата
//
Процедура УстановитьСертификат(ПараметрыУстановкиСертификата) Экспорт
	
	Оповещение = Новый ОписаниеОповещения("УстановитьСертификатПослеПодключенияКомпоненты",
		ЭтотОбъект, ПараметрыУстановкиСертификата);
	ВыполнитьПослеПроверкиРасширенияИКомпоненты(Оповещение);
	
КонецПроцедуры

// Получить корневой сертификат из данных сертификата и установить его.
// 
// Параметры:
//  ПараметрыУстановкиСертификата - см. ПараметрыУстановкиСертификата 
//                                - Структура:
//                                   * Сертификат - ДвоичныеДанные
//                                                - Строка - адрес во временном хранилище
//                                                - Строка - строковое представление сертификата в формате Base64
//                                                - СертификатКриптографии
//                                   * Хранилище - Структура:
//                                      ** Значение - Строка
//                                      ** Представление - Строка
//
Процедура УстановитьКорневойСертификат(ПараметрыУстановкиСертификата) Экспорт
	
	ПараметрыУстановки = ПараметрыУстановкиСертификата(ПараметрыУстановкиСертификата.Сертификат);
	ЗаполнитьЗначенияСвойств(ПараметрыУстановки, ПараметрыУстановкиСертификата);
	Оповещение = Новый ОписаниеОповещения("УстановитьКорневойСертификатПослеПодключенияКомпоненты",
		ЭтотОбъект, ПараметрыУстановки);
	ВыполнитьПослеПроверкиРасширенияИКомпоненты(Оповещение);
	
КонецПроцедуры 

// Параметры установки сертификата.
// 
// Параметры:
//  Сертификат - ДвоичныеДанные
//             - Строка - адрес во временном хранилище
//             - Строка - строковое представление сертификата в формате Base64
//             - СертификатКриптографии
// 
// Возвращаемое значение:
//  Структура:
//   * Сертификат - ДвоичныеДанные
//             - Строка - адрес во временном хранилище
//             - Строка - строковое представление сертификата в формате Base64
//             - СертификатКриптографии
//   * ОповещениеОЗавершении - ОписаниеОповещения - оповещение, которое вызывается после установки.
//                             Результат оповещения - Структура:
//                                       # УстановкаВыполнена - результат установки
//                                       # Сообщение - ошибка или сообщение о результате установки
//   * ВариантыУстановки - СписокЗначений - для выбора в форме установки
//   * Хранилище - Строка - имя хранилища
//               - Структура:
//                  ** Значение - имя хранилища
//                  ** Представление - представление в форме установки
//   * СвойстваКонтейнера - Структура:
//                           ** Имя - Строка - имя контейнера
//                           ** ТипПрограммы - Число - тип программы криптопровайдера
//                           ** ИмяПрограммы - Строка - имя программы криптопровайдера
//                           ** ПутьКПрограмме - Строка - имя программы криптопровайдера
//   * ТекстПредупреждения - Строка - для отображения в форме установки
//   * Форма - ФормаКлиентскогоПриложения - владелец формы установки
//
Функция ПараметрыУстановкиСертификата(Сертификат) Экспорт
	
	ПараметрыУстановкиСертификата = Новый Структура;
	ПараметрыУстановкиСертификата.Вставить("Сертификат", Сертификат);
	ПараметрыУстановкиСертификата.Вставить("ОповещениеОЗавершении", Неопределено);
	ПараметрыУстановкиСертификата.Вставить("ВариантыУстановки", Неопределено);
	ПараметрыУстановкиСертификата.Вставить("Хранилище", Неопределено);
	ПараметрыУстановкиСертификата.Вставить("СвойстваКонтейнера", Неопределено);
	ПараметрыУстановкиСертификата.Вставить("ТекстПредупреждения", "");
	ПараметрыУстановкиСертификата.Вставить("Форма", Неопределено);
	
	Возврат ПараметрыУстановкиСертификата;
	
КонецФункции

// Открывает окно ошибки.
// 
// Параметры:
//  ЗаголовокФормы - Строка - заголовок формы
//  ЗаголовокОшибки - Строка - заголовок ошибки
//  ОшибкаНаКлиенте - Структура:
//   * Ошибки - Массив
//  ОшибкаНаСервере - Структура
//  ДополнительныеПараметры - Неопределено, Структура:
//   * Сертификат 
//  ОбработкаПродолжения - ОписаниеОповещения - обработка продолжения
//
Процедура ПоказатьОшибкуОбращенияКПрограмме(ЗаголовокФормы, ЗаголовокОшибки, ОшибкаНаКлиенте, ОшибкаНаСервере,
				ДополнительныеПараметры = Неопределено, ОбработкаПродолжения = Неопределено) Экспорт
	
	Если ТипЗнч(ОшибкаНаКлиенте) <> Тип("Структура") Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Для процедуры %1
			           |указан некорректный тип параметра %2.'"),
				"ПоказатьОшибкуОбращенияКПрограмме", "ОшибкаНаКлиенте");
	КонецЕсли;
	
	Если ТипЗнч(ОшибкаНаСервере) <> Тип("Структура") Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Для процедуры %1
			           |указан некорректный тип параметра %2.'"),
				"ПоказатьОшибкуОбращенияКПрограмме", "ОшибкаНаСервере");
	КонецЕсли;
	
	ПараметрыФормы = Новый Структура;
	ПараметрыФормы.Вставить("ПоказатьИнструкцию",                Ложь);
	ПараметрыФормы.Вставить("ПоказатьПереходКНастройкеПрограмм", Ложь);
	ПараметрыФормы.Вставить("ПоказатьУстановкуРасширения",       Ложь);
	
	ДополнительныеДанные = Новый Структура;
	ДополнительныеДанные.Вставить("НеподписанныеДанные");
	ДополнительныеДанные.Вставить("Сертификат");
	ДополнительныеДанные.Вставить("Подпись");
	ДополнительныеДанные.Вставить("ДополнительныеДанныеПроверокНаКлиенте");
	ДополнительныеДанные.Вставить("ДополнительныеДанныеПроверокНаСервере");
	
	Если ТипЗнч(ДополнительныеПараметры) = Тип("Структура") Тогда
		ЗаполнитьЗначенияСвойств(ПараметрыФормы, ДополнительныеПараметры);
		ЗаполнитьЗначенияСвойств(ДополнительныеДанные, ДополнительныеПараметры);
	КонецЕсли;
	
	ПараметрыФормы.Вставить("ДополнительныеДанные", ДополнительныеДанные);
	
	ПараметрыФормы.Вставить("ЗаголовокФормы",  ЗаголовокФормы);
	ПараметрыФормы.Вставить("ЗаголовокОшибки", ЗаголовокОшибки);
	
	ПараметрыФормы.Вставить("ОшибкаНаКлиенте", ОшибкаНаКлиенте);
	ПараметрыФормы.Вставить("ОшибкаНаСервере", ОшибкаНаСервере);
	
	Контекст = Новый Структура;
	Контекст.Вставить("ПараметрыФормы", ПараметрыФормы);
	Контекст.Вставить("ОбработкаПродолжения", ОбработкаПродолжения);
	
	НачатьПодключениеРасширенияРаботыСКриптографией(Новый ОписаниеОповещения(
		"ПоказатьОшибкуОбращенияКПрограммеПослеПодключенияРасширения", ЭтотОбъект, Контекст));
	
КонецПроцедуры


// Открывает форму выбора сертификата.
// 
// Параметры:
//  СерверныеПараметры - Структура:
//   * Организация - ОпределяемыйТип.Организация 
//   * ФизическоеЛицо - ОпределяемыйТип.ФизическоеЛицо
//   * СертификатОснование - СправочникСсылка.СертификатыКлючейЭлектроннойПодписиИШифрования 
//   * ДляШифрованияИРасшифровки - Булево, Неопределено
//   * ДобавлениеВСписок - Булево
//   * ЛичныйСписокПриДобавлении - Булево 
//   * Организация - ОпределяемыйТип.Организация 
//  ВладелецНовойФормы - Неопределено, Форма -  владелец формы
//  ОбработчикЗавершения - Неопределено, ОписаниеОповещения
//
Процедура ВыборСертификатаДляПодписанияИлиРасшифровки(СерверныеПараметры, ВладелецНовойФормы = Неопределено, ОбработчикЗавершения = Неопределено) Экспорт
	
	Если ВладелецНовойФормы = Неопределено Тогда
		ВладелецНовойФормы = Новый УникальныйИдентификатор;
	КонецЕсли;
	
	Контекст = Новый Структура;
	Контекст.Вставить("СерверныеПараметры", СерверныеПараметры);
	Контекст.Вставить("ВладелецНовойФормы", ВладелецНовойФормы);
	Контекст.Вставить("ОбработчикЗавершения", ОбработчикЗавершения);
	
	Если ЭлектроннаяПодписьКлиент.СоздаватьЭлектронныеПодписиНаСервере()
	   И СерверныеПараметры.Свойство("ВыполнятьНаСервере")
	   И СерверныеПараметры.ВыполнятьНаСервере = Истина Тогда
		
		Результат = Новый Структура;
		Результат.Вставить("СвойстваСертификатовНаКлиенте", Новый Массив);
		Результат.Вставить("ОшибкаПолученияСертификатовНаКлиенте", Новый Структура);
		
		ВыборСертификатаДляПодписанияИлиРасшифровкиПродолжение(Результат, Контекст);
	Иначе
		ПолучитьСвойстваСертификатовНаКлиенте(Новый ОписаниеОповещения(
			"ВыборСертификатаДляПодписанияИлиРасшифровкиПродолжение", ЭтотОбъект, Контекст), Истина, Ложь);
	КонецЕсли;
	
КонецПроцедуры

// См. ЭлектроннаяПодпись.СвойстваСертификата
Асинх Функция СвойстваСертификата(Сертификат) Экспорт
	
	Если ТипЗнч(Сертификат) = Тип("СертификатКриптографии") Тогда
		ДвоичныеДанныеСертификата = Ждать Сертификат.ВыгрузитьАсинх();
	ИначеЕсли ТипЗнч(Сертификат) = Тип("ФиксированнаяСтруктура") Тогда
		ДвоичныеДанныеСертификата = Сертификат.Сертификат;
	Иначе
		ДвоичныеДанныеСертификата = Неопределено;
	КонецЕсли;
			
	Возврат ЭлектроннаяПодписьСлужебныйКлиентСервер.СвойстваСертификата(Сертификат,
		ДобавкаВремени(), ДвоичныеДанныеСертификата);
		
КонецФункции

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

Функция ИспользуетсяИнтерактивныйРежимКриптографии(МенеджерКриптографии) Экспорт
	
	Если МенеджерКриптографии.ИспользованиеИнтерактивногоРежима = ИспользованиеИнтерактивногоРежимаКриптографииИспользовать() Тогда
		Возврат Истина;
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

// В ОС Linux и MacOS при создании менеджера криптографии
// требуется указывать путь к программе.
//
// Возвращаемое значение:
//  Булево
//
Функция ТребуетсяПутьКПрограмме() Экспорт
	
	Возврат ОбщегоНазначенияКлиент.ЭтоLinuxКлиент()
		Или ОбщегоНазначенияКлиент.ЭтоMacOSКлиент();
	
КонецФункции

Процедура ПолучитьПутьКПрограмме(ОбработкаЗавершения, ПрограммаСсылка) Экспорт
	
	Результат = Новый Структура("ПутьКПрограмме, Существует", "", Ложь);
	
	Если Не ТребуетсяПутьКПрограмме() Тогда
		ВыполнитьОбработкуОповещения(ОбработкаЗавершения, Результат);
		Возврат;
	КонецЕсли;
	
	Контекст = Новый Структура;
	Контекст.Вставить("ОбработкаЗавершения", ОбработкаЗавершения);
	Контекст.Вставить("ПрограммаСсылка", ПрограммаСсылка);
	ПроверенныеПутиКМодулямПрограмм = ПроверенныеПутиКМодулямПрограмм();
	
	ОписаниеПути = ПроверенныеПутиКМодулямПрограмм.Получить(ПрограммаСсылка);
	Если ОписаниеПути <> Неопределено Тогда
		ПолучитьПутьКПрограммеЗавершение(ОписаниеПути, Контекст);
		Возврат;
	КонецЕсли;
	Контекст.Вставить("ПроверенныеПутиКМодулямПрограмм", ПроверенныеПутиКМодулямПрограмм);
	
	ПерсональныеНастройки = ЭлектроннаяПодписьКлиент.ПерсональныеНастройки();
	ПутьКПрограмме = ПерсональныеНастройки.ПутиКПрограммамЭлектроннойПодписиИШифрования.Получить(
		ПрограммаСсылка);
	
	Если ЗначениеЗаполнено(ПутьКПрограмме) Тогда
		Контекст.Вставить("Результат", Результат);
		Результат.ПутьКПрограмме = ПутьКПрограмме;
		ПроверитьПутьКПрограмме(Новый ОписаниеОповещения(
			"ПолучитьПутьКПрограммеПослеПроверкиПути", ЭтотОбъект, Контекст), ПутьКПрограмме);
	Иначе
		ПолучитьПутьКПрограммеПоУмолчанию(Новый ОписаниеОповещения(
			"ПолучитьПутьКПрограммеЗавершение", ЭтотОбъект, Контекст), ПрограммаСсылка);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ПолучитьПутьКПрограмме.
Процедура ПолучитьПутьКПрограммеПослеПроверкиПути(Существует, Контекст) Экспорт
	
	Контекст.Результат.Существует = Существует;
	ПолучитьПутьКПрограммеЗавершение(Контекст.Результат, Контекст);
	
КонецПроцедуры

// Продолжение процедуры ПолучитьПутьКПрограмме.
Процедура ПолучитьПутьКПрограммеЗавершение(ОписаниеПути, Контекст) Экспорт
	
	Если Контекст.Свойство("ПроверенныеПутиКМодулямПрограмм") Тогда
		Контекст.ПроверенныеПутиКМодулямПрограмм.Вставить(Контекст.ПрограммаСсылка, ОписаниеПути);
	КонецЕсли;
	
	Результат = Новый Структура("ПутьКПрограмме, Существует",
		ОписаниеПути.ПутьКПрограмме, ОписаниеПути.Существует <> Ложь);
	
	ВыполнитьОбработкуОповещения(Контекст.ОбработкаЗавершения, Результат);
	
КонецПроцедуры

Функция ПроверенныеПутиКМодулямПрограмм()
	
	ОбщиеНастройки = ЭлектроннаяПодписьКлиент.ОбщиеНастройки();
	
	ИмяПараметра = "СтандартныеПодсистемы.ЭлектроннаяПодпись.ОписаниеПутейКМодулямПрограмм";
	ОписаниеПутейКМодулямПрограмм = ПараметрыПриложения.Получить(ИмяПараметра);
	
	Если ОписаниеПутейКМодулямПрограмм = Неопределено
	 Или ОписаниеПутейКМодулямПрограмм.ВерсияНастроек <> ОбщиеНастройки.ВерсияНастроек Тогда
		
		ОписаниеПутейКМодулямПрограмм = Новый Структура("ПутиКМодулямПрограмм, ВерсияНастроек",
			Новый Соответствие, ОбщиеНастройки.ВерсияНастроек);
		
		ПараметрыПриложения.Вставить(ИмяПараметра, ОписаниеПутейКМодулямПрограмм);
	КонецЕсли;
	
	Возврат ОписаниеПутейКМодулямПрограмм.ПутиКМодулямПрограмм;
	
КонецФункции

Процедура ПроверитьПутьКПрограмме(ОбработкаЗавершения, ПутьКПрограмме)
	
	Контекст = Новый Структура;
	Контекст.Вставить("ОбработкаЗавершения", ОбработкаЗавершения);
	Контекст.Вставить("ПутьКПрограмме", ПутьКПрограмме);
	
	ФайловаяСистемаКлиент.ПодключитьРасширениеДляРаботыСФайлами(Новый ОписаниеОповещения(
		"ПроверитьПутьКПрограммеПослеПодключенияРасширенияРаботыСФайлами", ЭтотОбъект, Контекст));
	
КонецПроцедуры

// Продолжение процедуры ПроверитьПутьКПрограмме.
Процедура ПроверитьПутьКПрограммеПослеПодключенияРасширенияРаботыСФайлами(РасширениеПодключено, Контекст) Экспорт
	
	Если Не РасширениеПодключено Тогда
		ВыполнитьОбработкуОповещения(Контекст.ОбработкаЗавершения, Неопределено);
		Возврат;
	КонецЕсли;
	
	Контекст.Вставить("ПутиКМодулям", СтрРазделить(Контекст.ПутьКПрограмме, ":", Ложь));
	Контекст.Вставить("Индекс", -1);
	
	ПроверитьПутьКПрограммеЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ПроверитьПутьКПрограмме.
//
// Параметры:
//  Контекст - Структура
//
Процедура ПроверитьПутьКПрограммеЦиклНачало(Контекст)
	
	Если Контекст.ПутиКМодулям.Количество() <= Контекст.Индекс + 1 Тогда
		// После цикла.
		ВыполнитьОбработкуОповещения(Контекст.ОбработкаЗавершения, Ложь);
		Возврат;
	КонецЕсли;
	
	Контекст.Индекс = Контекст.Индекс + 1;
	
	Файл = Новый Файл;
	Файл.НачатьИнициализацию(Новый ОписаниеОповещения(
		"ПроверитьПутьКПрограммеЦиклПослеИнициализацииФайла", ЭтотОбъект, Контекст),
		Контекст.ПутиКМодулям[Контекст.Индекс]);
	
КонецПроцедуры

// Продолжение процедуры ПроверитьПутьКПрограмме.
Процедура ПроверитьПутьКПрограммеЦиклПослеИнициализацииФайла(Файл, Контекст) Экспорт
	
	Файл.НачатьПроверкуСуществования(Новый ОписаниеОповещения(
		"ПроверитьПутьКПрограммеЦиклПослеПроверкиСуществованияФайла", ЭтотОбъект, Контекст));
	
КонецПроцедуры

// Продолжение процедуры ПроверитьПутьКПрограмме.
Процедура ПроверитьПутьКПрограммеЦиклПослеПроверкиСуществованияФайла(Существует, Контекст) Экспорт
	
	Если Существует Тогда
		ВыполнитьОбработкуОповещения(Контекст.ОбработкаЗавершения, Истина);
		Возврат;
	КонецЕсли;
	
	ПроверитьПутьКПрограммеЦиклНачало(Контекст);
	
КонецПроцедуры

Процедура ПолучитьПутьКПрограммеПоУмолчанию(ОбработкаЗавершения, ПрограммаСсылка) Экспорт
	
	Результат = Новый Структура("ПутьКПрограмме, Существует", "", Ложь);
	
	Если Не ТребуетсяПутьКПрограмме() Тогда
		ВыполнитьОбработкуОповещения(ОбработкаЗавершения, Результат);
		Возврат;
	КонецЕсли;
	
	ОбщиеНастройки = ЭлектроннаяПодписьКлиент.ОбщиеНастройки();
	Если ТипЗнч(ПрограммаСсылка) = Тип("Строка") Тогда
		ИдентификаторПрограммы = ПрограммаСсылка;
	Иначе
		ОписаниеПрограммы = ОбщиеНастройки.ОписанияПрограммПоСсылке.Получить(ПрограммаСсылка); // см. ЭлектроннаяПодписьСлужебныйПовтИсп.ОписаниеПрограммы
		Если ОписаниеПрограммы = Неопределено Тогда
			ВыполнитьОбработкуОповещения(ОбработкаЗавершения, Результат);
			Возврат;
		КонецЕсли;
		ИдентификаторПрограммы = ОписаниеПрограммы.Идентификатор;
	КонецЕсли;
	
	ПутиНайдены = Ложь;
	Для Каждого ПутиКМодулямПрограмм Из ОбщиеНастройки.ПоставляемыеПутиКМодулямПрограмм Цикл
		Если СтрНачинаетсяС(ИдентификаторПрограммы, ПутиКМодулямПрограмм.Ключ) Тогда
			ПутиНайдены = Истина;
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Если Не ПутиНайдены Тогда
		ВыполнитьОбработкуОповещения(ОбработкаЗавершения, Результат);
		Возврат;
	КонецЕсли;
	
	ПутиКМодулямПрограммы = ПутиКМодулямПрограмм.Значение.Получить(
		ОбщегоНазначенияКлиентСервер.ИмяТипаПлатформы());
	
	Если ПутиКМодулямПрограммы = Неопределено Тогда
		ВыполнитьОбработкуОповещения(ОбработкаЗавершения, Результат);
		Возврат;
	КонецЕсли;
	
	Контекст = Новый Структура;
	Контекст.Вставить("ОбработкаЗавершения", ОбработкаЗавершения);
	Контекст.Вставить("ПутиКМодулямПрограммы", ПутиКМодулямПрограммы);
	Контекст.Вставить("Индекс", -1);
	
	ПолучитьПутьКПрограммеПоУмолчаниюЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ПолучитьПутьКПрограммеПоУмолчанию.
Процедура ПолучитьПутьКПрограммеПоУмолчаниюЦиклНачало(Контекст)
	
	Если Контекст.ПутиКМодулямПрограммы.Количество() <= Контекст.Индекс + 1 Тогда
		// После цикла.
		ПолучитьПутьКПрограммеПоУмолчаниюЦиклЗавершение(Контекст, Ложь);
		Возврат;
	КонецЕсли;
	
	Контекст.Индекс = Контекст.Индекс + 1;
	
	ПроверитьПутьКПрограмме(Новый ОписаниеОповещения(
		"ПолучитьПутьКПрограммеПоУмолчаниюЦиклПослеПроверкиПути", ЭтотОбъект, Контекст),
		Контекст.ПутиКМодулямПрограммы.Получить(Контекст.Индекс))
	
КонецПроцедуры

// Продолжение процедуры ПолучитьПутьКПрограммеПоУмолчанию.
Процедура ПолучитьПутьКПрограммеПоУмолчаниюЦиклПослеПроверкиПути(Существует, Контекст) Экспорт
	
	Если Существует <> Ложь Тогда
		ПолучитьПутьКПрограммеПоУмолчаниюЦиклЗавершение(Контекст, Существует);
		Возврат;
	КонецЕсли;
	
	ПолучитьПутьКПрограммеПоУмолчаниюЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ПолучитьПутьКПрограммеПоУмолчанию.
Процедура ПолучитьПутьКПрограммеПоУмолчаниюЦиклЗавершение(Контекст, Существует)
	
	ТекущийПуть = Контекст.ПутиКМодулямПрограммы.Получить(
		?(Существует <> Истина, 0, Контекст.Индекс));
	
	Результат = Новый Структура("ПутьКПрограмме, Существует", ТекущийПуть, Существует);
	
	ВыполнитьОбработкуОповещения(Контекст.ОбработкаЗавершения, Результат);
	
КонецПроцедуры

// Продолжение процедуры НайтиДействительныеЛичныеСертификаты.
Процедура НайтиДействительныеЛичныеСертификаты(Оповещение, Отбор = Неопределено) Экспорт
	
	ПараметрыОповещения = Новый Структура;
	ПараметрыОповещения.Вставить("ОповещениеОЗавершении", Оповещение);
	
	Если Отбор = Неопределено Тогда
		Отбор = Новый Структура;
	КонецЕсли;
	
	Если Не Отбор.Свойство("ПроверятьСрокДействия") Тогда
		Отбор.Вставить("ПроверятьСрокДействия", Истина);
	КонецЕсли;
	
	Если Не Отбор.Свойство("ТолькоСертификатыСЗаполненнойПрограммой") Тогда
		Отбор.Вставить("ТолькоСертификатыСЗаполненнойПрограммой", Истина);
	КонецЕсли;
	
	Если Не Отбор.Свойство("ВключатьСертификатыСПустымПользователем") Тогда
		Отбор.Вставить("ВключатьСертификатыСПустымПользователем", Истина);
	КонецЕсли;
	
	Если Не Отбор.Свойство("Организация") Тогда
		Отбор.Вставить("Организация", Неопределено);
	КонецЕсли;

	ПараметрыОповещения.Вставить("Отбор",                 Отбор);
	
	Оповещение = Новый ОписаниеОповещения("НайтиДействительныеЛичныеСертификатыПослеПолученияПодписейНаКлиенте", ЭтотОбъект, ПараметрыОповещения);
	ПолучитьСвойстваСертификатовНаКлиенте(Оповещение, Не Отбор.ПроверятьСрокДействия, Истина);
	
КонецПроцедуры

// Продолжение процедуры НайтиДействительныеЛичныеСертификаты.
Процедура НайтиДействительныеЛичныеСертификатыПослеПолученияПодписейНаКлиенте(Результат, ДополнительныеПараметры) Экспорт

	ЛичныеСертификаты = ЭлектроннаяПодписьСлужебныйВызовСервера.ЛичныеСертификаты(Результат.СвойстваСертификатовНаКлиенте, ДополнительныеПараметры.Отбор);
	ВыполнитьОбработкуОповещения(ДополнительныеПараметры.ОповещениеОЗавершении, ЛичныеСертификаты);
	
КонецПроцедуры

// Продолжение процедуры ПроверитьУстановкуПрограммКриптографии.
Процедура ПроверитьУстановкуПрограммКриптографии(Форма, ПараметрыПроверки = Неопределено, ОповещениеОЗавершении = Неопределено) Экспорт
	
	Контекст = Новый Структура;
	Контекст.Вставить("Форма", Форма);
	Контекст.Вставить("ЭтоПовторнаяПроверка", Ложь);
	Контекст.Вставить("ПредлагатьУстановитьПрограмму", Неопределено);
	Контекст.Вставить("ПроверяемыеПрограммы", Неопределено);
	Контекст.Вставить("РасширенноеОписание", Ложь);
	Контекст.Вставить("Оповещение", ОповещениеОЗавершении);
	
	ПараметрыПолучения = Новый Структура;
	ПараметрыПолучения.Вставить("УстанавливатьКомпоненту", Истина);
	ПараметрыПолучения.Вставить("УстанавливатьРасширение", Истина);
	ПараметрыПолучения.Вставить("ПроверятьНаСервере",      Неопределено);
	
	Если ТипЗнч(ПараметрыПроверки) = Тип("Структура") Тогда
		ЗаполнитьЗначенияСвойств(Контекст, ПараметрыПроверки);
		ЗаполнитьЗначенияСвойств(ПараметрыПолучения, ПараметрыПроверки);
	КонецЕсли;
	
	Если Контекст.ПредлагатьУстановитьПрограмму = Неопределено Тогда
		Контекст.ПредлагатьУстановитьПрограмму = Контекст.ПроверяемыеПрограммы = Истина
			И Не ЭлектроннаяПодписьКлиент.ПроверятьЭлектронныеПодписиНаСервере()
			И Не ЭлектроннаяПодписьКлиент.СоздаватьЭлектронныеПодписиНаСервере()
			И Не ИспользоватьСервисОблачнойПодписи()
			И Не ИспользоватьЭлектроннуюПодписьВМоделиСервиса();
	КонецЕсли;
	
	Контекст.Вставить("АлгоритмыПодписи", Новый Массив);
	Контекст.Вставить("ТипДанных", Неопределено);
		
	Если Контекст.ПроверяемыеПрограммы <> Неопределено Тогда
		Если Контекст.ПроверяемыеПрограммы = Истина Тогда
			Контекст.ПроверяемыеПрограммы = Неопределено;
			Контекст.АлгоритмыПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.АктуальныеАлгоритмыПрограмм();
			Контекст.ТипДанных = "Сертификат";
		ИначеЕсли ТипЗнч(Контекст.ПроверяемыеПрограммы) = Тип("ДвоичныеДанные")
			Или ТипЗнч(Контекст.ПроверяемыеПрограммы) = Тип("Строка") Тогда
			ДвоичныеДанные = ЭлектроннаяПодписьСлужебныйКлиентСервер.ДвоичныеДанныеИзДанных(
				Контекст.ПроверяемыеПрограммы, "ЭлектроннаяПодписьСлужебныйКлиент.ПроверитьУстановкуПрограммКриптографии");
			Контекст.ПроверяемыеПрограммы = Неопределено;
			Контекст.ТипДанных = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОпределитьТипДанных(ДвоичныеДанные);
			Если Контекст.ТипДанных = "Сертификат" Тогда
				АлгоритмПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.АлгоритмПодписиСертификата(ДвоичныеДанные);
			ИначеЕсли Контекст.ТипДанных = "Подпись" Тогда
				АлгоритмПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.АлгоритмСформированнойПодписи(ДвоичныеДанные);
			Иначе
				ВызватьИсключение НСтр("ru = 'Данные для поиска программы криптографии не являются сертификатом или подписью.'");
			КонецЕсли;
			Контекст.АлгоритмыПодписи.Добавить(АлгоритмПодписи);
		КонецЕсли;
	КонецЕсли;
	
	ПолучитьУстановленныеКриптопровайдеры(
		Новый ОписаниеОповещения("ПроверитьУстановкуПрограммКриптографииПослеПолученияУстановленных", ЭтотОбъект, Контекст),
		ПараметрыПолучения);

КонецПроцедуры

// Продолжение процедуры НайтиУстановленныеПрограммы.
Процедура НайтиУстановленныеПрограммы(Оповещение, ОписаниеПрограмм, ПроверятьНаСервере) Экспорт
	
	Программы = ЭлектроннаяПодписьСлужебныйВызовСервера.НайтиУстановленныеПрограммы(
		ОписаниеПрограмм, ПроверятьНаСервере);
	
	Контекст = КонтекстПоискаУстановленныхПрограмм();
	Контекст.Индекс = -1;
	Контекст.Программы = Программы;
	Контекст.ОповещениеОЗавершении = Оповещение;
	
	Оповещение = Новый ОписаниеОповещения("НайтиУстановленныеПрограммыПослеПодключенияРасширения", ЭтотОбъект, Контекст);
	ЭлектроннаяПодписьКлиент.УстановитьРасширение(Истина, Оповещение);
	
КонецПроцедуры

// Продолжение процедуры НайтиУстановленныеПрограммы.
Процедура НайтиУстановленныеПрограммыПослеПодключенияРасширения(Подключено, Контекст) Экспорт
	
	НайтиУстановленныеПрограммыЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры НайтиУстановленныеПрограммы.
Процедура НайтиУстановленныеПрограммыЦиклНачало(Контекст)
	
	Если Контекст.Программы.Количество() <= Контекст.Индекс + 1 Тогда
		НайтиУстановленныеПрограммыПослеЦикла(Контекст);
		Возврат;
	КонецЕсли;
	Контекст = Контекст; // см. КонтекстПоискаУстановленныхПрограмм
	Контекст.Индекс = Контекст.Индекс + 1;
	
	ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
	ПараметрыСоздания.Программа = Контекст.Программы.Получить(Контекст.Индекс);
	ПараметрыСоздания.ПоказатьОшибку = Неопределено;
	
	Оповещение = Новый ОписаниеОповещения("НайтиУстановленныеПрограммыЦиклПродолжение", ЭтотОбъект, Контекст);
	СоздатьМенеджерКриптографии(Оповещение, "", ПараметрыСоздания);
	
КонецПроцедуры

// Продолжение процедуры НайтиУстановленныеПрограммы.
Процедура НайтиУстановленныеПрограммыЦиклПродолжение(Результат, Контекст) Экспорт
	
	Контекст = Контекст; // см. КонтекстПоискаУстановленныхПрограмм
	ОписаниеПрограммы = Контекст.Программы.Получить(Контекст.Индекс);
	
	Если ТипЗнч(Результат) = Тип("МенеджерКриптографии") Тогда
		ОписаниеПрограммы.РезультатПроверкиНаКлиенте = "";
		ОписаниеПрограммы.Установлена = Истина;
	Иначе
		ОписаниеПрограммы.РезультатПроверкиНаКлиенте =
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ТекстОшибкиПоискаПрограммы(
				НСтр("ru = 'Не установлена на компьютере.'"), Результат);
	КонецЕсли;
	
	НайтиУстановленныеПрограммыЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры НайтиУстановленныеПрограммы.
Процедура НайтиУстановленныеПрограммыПослеЦикла(Контекст)
	
	Для Каждого Программа Из Контекст.Программы Цикл
		Программа.Удалить("Идентификатор");
	КонецЦикла;
	
	ВыполнитьОбработкуОповещения(Контекст.ОповещениеОЗавершении, Контекст.Программы);
	
КонецПроцедуры

// Открывает форму просмотра данных сертификата.
//
// Параметры:
//  ДанныеСертификата - СправочникСсылка.СертификатыКлючейЭлектроннойПодписиИШифрования - ссылка на сертификат.
//                    - СертификатКриптографии - имеющийся сертификат.
//                    - ДвоичныеДанные - двоичные данные сертификата.
//                    - Строка - адрес временного хранилища содержащий ДвоичныеДанные сертификата.
//                    - Строка - отпечаток сертификата для поиска во всех хранилищах.
//
//  ОткрытьДанные     - Булево - открыть данные сертификата, а не форму элемента справочника.
//                      Если передана не ссылка на элемент справочника и элемент справочника
//                      не удалось найти по отпечатку, тогда будут открыты данные сертификата.
//
Процедура ОткрытьСертификат(ДанныеСертификата, ОткрытьДанные = Ложь) Экспорт
	
	Контекст = КонтекстОткрытияСертификата();
	Контекст.ДанныеСертификата = ДанныеСертификата;
	Контекст.ОткрытьДанные = ОткрытьДанные;
	Контекст.АдресСертификата = Неопределено;
	
	Если ТипЗнч(ДанныеСертификата) = Тип("СертификатКриптографии") Тогда
		ДанныеСертификата.НачатьВыгрузку(Новый ОписаниеОповещения(
			"ОткрытьСертификатПослеВыгрузкиСертификата", ЭтотОбъект, Контекст));
	Иначе
		ОткрытьСертификатПродолжение(Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Возвращаемое значение:
//   Структура:
//   * АдресСертификата - Строка
//   * ОткрытьДанные - см. ОткрытьСертификат.ОткрытьДанные
//   * ДанныеСертификата - см. ОткрытьСертификат.ДанныеСертификата


// Контекст открытия сертификата.
// 
// Возвращаемое значение:
//  Структура - контекст открытия сертификата:
//   * ДанныеСертификата - см. ОткрытьСертификат.ДанныеСертификата
//   * ОткрытьДанные - см. ОткрытьСертификат.ОткрытьДанные
//   * АдресСертификата - Строка
//   * Ссылка - СправочникСсылка.СертификатыКлючейЭлектроннойПодписиИШифрования
//   * Отпечаток - Строка
//   * ОшибкаНаКлиенте - Структура
//
Функция КонтекстОткрытияСертификата()
	Контекст = Новый Структура;
	Контекст.Вставить("ДанныеСертификата");
	Контекст.Вставить("ОткрытьДанные");
	Контекст.Вставить("АдресСертификата");
	Контекст.Вставить("Ссылка");
	Контекст.Вставить("Отпечаток");
	Контекст.Вставить("ОшибкаНаКлиенте", Новый Структура);
	Возврат Контекст;
КонецФункции

// Продолжение процедуры ОткрытьСертификат.
Процедура ОткрытьСертификатПослеВыгрузкиСертификата(ВыгруженныеДанные, Контекст) Экспорт
	
	Контекст.АдресСертификата = ПоместитьВоВременноеХранилище(ВыгруженныеДанные);
	
	ОткрытьСертификатПродолжение(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ОткрытьСертификат.
Процедура ОткрытьСертификатПродолжение(Контекст)
	
	Если Контекст.АдресСертификата <> Неопределено Тогда
		// Сертификат подготовлен.
		
	ИначеЕсли ТипЗнч(Контекст.ДанныеСертификата) = Тип("СправочникСсылка.СертификатыКлючейЭлектроннойПодписиИШифрования") Тогда
		Ссылка = Контекст.ДанныеСертификата;
		
	ИначеЕсли ТипЗнч(Контекст.ДанныеСертификата) = Тип("ДвоичныеДанные") Тогда
		Контекст.АдресСертификата = ПоместитьВоВременноеХранилище(Контекст.ДанныеСертификата);
		
	ИначеЕсли ТипЗнч(Контекст.ДанныеСертификата) <> Тип("Строка") Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Ошибка при вызове процедуры %1 общего модуля %2:
			           |Некорректное значение параметра %3 ""%4"".'"),
				"ОткрытьСертификат", "ЭлектроннаяПодписьКлиент", "ДанныеСертификата", Строка(Контекст.ДанныеСертификата));
		
	ИначеЕсли ЭтоАдресВременногоХранилища(Контекст.ДанныеСертификата) Тогда
		Контекст.АдресСертификата = Контекст.ДанныеСертификата;
	Иначе
		Отпечаток = Строка(Контекст.ДанныеСертификата); // Строка
	КонецЕсли;
	
	Если Не Контекст.ОткрытьДанные Тогда
		Если Ссылка = Неопределено Тогда
			Ссылка = ЭлектроннаяПодписьСлужебныйВызовСервера.СсылкаНаСертификат(Отпечаток, Контекст.АдресСертификата);
		КонецЕсли;
		Если ЗначениеЗаполнено(Ссылка) Тогда
			ПоказатьЗначение(, Ссылка);
			Возврат;
		КонецЕсли;
	КонецЕсли;
	
	Контекст.Ссылка = Ссылка;
	Контекст.Отпечаток = Отпечаток;
	
	Если Контекст.АдресСертификата = Неопределено
	   И Ссылка = Неопределено Тогда
		
		ПолучитьСертификатПоОтпечатку(Новый ОписаниеОповещения(
			"ОткрытьСертификатПослеПоискаСертификата", ЭтотОбъект, Контекст), Отпечаток, Ложь, Неопределено);
	Иначе
		ОткрытьСертификатЗавершение(Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ОткрытьСертификат.
Процедура ОткрытьСертификатПослеПоискаСертификата(Результат, Контекст) Экспорт
	
	Если ТипЗнч(Результат) = Тип("СертификатКриптографии") Тогда
		Результат.НачатьВыгрузку(Новый ОписаниеОповещения(
			"ОткрытьСертификатПослеВыгрузкиНайденногоСертификата", ЭтотОбъект, Контекст));
	Иначе
		Контекст.ОшибкаНаКлиенте = Результат;
		ОткрытьСертификатЗавершение(Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ОткрытьСертификат.
Процедура ОткрытьСертификатПослеВыгрузкиНайденногоСертификата(ВыгруженныеДанные, Контекст) Экспорт
	
	Контекст.АдресСертификата = ПоместитьВоВременноеХранилище(ВыгруженныеДанные);
	
	ОткрытьСертификатЗавершение(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ОткрытьСертификат.
Процедура ОткрытьСертификатЗавершение(Контекст)
	
	ПараметрыФормы = Новый Структура;
	ПараметрыФормы.Вставить("Ссылка");
	ПараметрыФормы.Вставить("АдресСертификата");
	ПараметрыФормы.Вставить("Отпечаток");
	ПараметрыФормы.Вставить("ОшибкаНаКлиенте");
	
	ЗаполнитьЗначенияСвойств(ПараметрыФормы, Контекст);
	
	ОткрытьФорму("ОбщаяФорма.Сертификат", ПараметрыФормы);
	
КонецПроцедуры

// Сохраняет сертификат в файл.
// 
// Параметры:
//   Оповещение - ОписаниеОповещения - вызывается после сохранения.
//              - Неопределено - продолжение не требуется.
//
//   Сертификат - СертификатКриптографии - сертификат.
//              - ДвоичныеДанные - двоичные данные сертификата.
//              - Строка - адрес временного хранилища, содержащего двоичные данные сертификата.
//
Процедура СохранитьСертификат(Оповещение, Сертификат, ИмяФайлаБезРасширения = "") Экспорт
	
	Контекст =  КонтекстСохраненияСертификата();
	Контекст.Оповещение =            Оповещение;
	Контекст.Сертификат =            Сертификат;
	Контекст.ИмяФайлаБезРасширения = ИмяФайлаБезРасширения;
	Контекст.АдресСертификата =      Неопределено;
	
	Если ТипЗнч(Сертификат) = Тип("СертификатКриптографии") Тогда
		Сертификат.НачатьВыгрузку(Новый ОписаниеОповещения(
			"СохранитьСертификатПослеВыгрузкиСертификата", ЭтотОбъект, Контекст));
	Иначе
		СохранитьСертификатПродолжение(Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Возвращаемое значение:
//   Структура:
//   * АдресСертификата - Строка
//   * ИмяФайлаБезРасширения - Строка
//   * Сертификат - см. СохранитьСертификат.Сертификат
//   * Оповещение - см. СохранитьСертификат.Оповещение
//
Функция КонтекстСохраненияСертификата()
	Контекст =  Новый Структура;
	Контекст.Вставить("Оповещение");
	Контекст.Вставить("Сертификат");
	Контекст.Вставить("ИмяФайлаБезРасширения");
	Контекст.Вставить("АдресСертификата");
	
	Возврат Контекст;
КонецФункции

// Продолжение процедуры СохранитьСертификат.
Процедура СохранитьСертификатПослеВыгрузкиСертификата(ВыгруженныеДанные, Контекст) Экспорт
	
	Контекст.АдресСертификата = ПоместитьВоВременноеХранилище(ВыгруженныеДанные, Новый УникальныйИдентификатор);
	Контекст.Вставить("УдалитьСертификатИзВременногоХранилища", Истина);
	СохранитьСертификатПродолжение(Контекст);
	
КонецПроцедуры

// Продолжение процедуры СохранитьСертификат.
Процедура СохранитьСертификатПродолжение(Контекст)
	
	Если Контекст.АдресСертификата <> Неопределено Тогда
		// Сертификат подготовлен.
		
	ИначеЕсли ТипЗнч(Контекст.Сертификат) = Тип("ДвоичныеДанные") Тогда
		Контекст.АдресСертификата = ПоместитьВоВременноеХранилище(Контекст.Сертификат, Новый УникальныйИдентификатор);
		Контекст.Вставить("УдалитьСертификатИзВременногоХранилища", Истина);
	ИначеЕсли ТипЗнч(Контекст.Сертификат) = Тип("Строка")
		И ЭтоАдресВременногоХранилища(Контекст.Сертификат) Тогда
		
		Контекст.АдресСертификата = Контекст.Сертификат;
	Иначе
		Если Контекст.Оповещение <> Неопределено Тогда
			ВыполнитьОбработкуОповещения(Контекст.Оповещение, Ложь);
		КонецЕсли;
		Возврат;
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(Контекст.ИмяФайлаБезРасширения) Тогда
		Контекст.ИмяФайлаБезРасширения = ЭлектроннаяПодписьСлужебныйВызовСервера.ПредставлениеСубъекта(Контекст.АдресСертификата);
	КонецЕсли;
	
	ИмяФайла = ЭлектроннаяПодписьСлужебныйКлиентСервер.ПодготовитьСтрокуДляИмениФайла(
		Контекст.ИмяФайлаБезРасширения) + ".cer";
	
	Оповещение = Новый ОписаниеОповещения("СохранитьСертификатПослеПолученияФайлов", ЭтотОбъект, Контекст);
	
	ПараметрыСохранения = ФайловаяСистемаКлиент.ПараметрыСохраненияФайла();
	ПараметрыСохранения.Диалог.Заголовок = НСтр("ru = 'Выберите файл для сохранения сертификата'");
	ПараметрыСохранения.Диалог.Фильтр    = НСтр("ru = 'Файлы сертификатов (*.cer)|*.cer'")+ "|"
		+ СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Все файлы (%1)|%1'"), ПолучитьМаскуВсеФайлы());
	
	ФайловаяСистемаКлиент.СохранитьФайл(Оповещение, Контекст.АдресСертификата, ИмяФайла, ПараметрыСохранения);
	
КонецПроцедуры

// Продолжение процедуры СохранитьСертификат.
// 
// Параметры:
//   ПолученныеФайлы - Массив из ОписаниеПереданногоФайла
//   Контекст - Структура
//
Процедура СохранитьСертификатПослеПолученияФайлов(ПолученныеФайлы, Контекст) Экспорт
	
	Если ПолученныеФайлы = Неопределено
	 Или ПолученныеФайлы.Количество() = 0 Тогда
		
		ЕстьПолученныеФайлы = Ложь;
	Иначе
		ЕстьПолученныеФайлы = Истина;
		ПоказатьОповещениеПользователя(НСтр("ru = 'Сертификат сохранен в файл:'"),,
			ПолученныеФайлы[0].Имя);
	КонецЕсли;
	
	Если Контекст.Свойство("УдалитьСертификатИзВременногоХранилища") Тогда
		УдалитьИзВременногоХранилища(Контекст.АдресСертификата);
	КонецЕсли;
	
	Если Контекст.Оповещение <> Неопределено Тогда
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, ЕстьПолученныеФайлы);
	КонецЕсли;
	
КонецПроцедуры

// Сохраняет подпись на компьютер.
Процедура СохранитьПодпись(АдресПодписи) Экспорт
	
	Оповещение = Новый ОписаниеОповещения("СохранитьПодписьПослеПолученияФайла", ЭтотОбъект, Неопределено);
	Фильтр = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Файлы электронных подписей (*.%1)|*.%1'"),
		ЭлектроннаяПодписьКлиент.ПерсональныеНастройки().РасширениеДляФайловПодписи);
	Фильтр = Фильтр + "|" + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Все файлы (%1)|%1'"), ПолучитьМаскуВсеФайлы());
	
	ПараметрыСохранения = ФайловаяСистемаКлиент.ПараметрыСохраненияФайла();
	ПараметрыСохранения.Диалог.Фильтр = Фильтр;
	ПараметрыСохранения.Диалог.Заголовок = НСтр("ru = 'Выберите файл для сохранения подписи'");
	
	ФайловаяСистемаКлиент.СохранитьФайл(Оповещение, АдресПодписи, "", ПараметрыСохранения);
	
КонецПроцедуры

// Продолжение процедуры СохранитьПодпись.
// 
// Параметры:
//   ПолученныеФайлы - Массив из ОписаниеПереданногоФайла
//   Контекст - Структура
//
Процедура СохранитьПодписьПослеПолученияФайла(ПолученныеФайлы, Контекст) Экспорт
	
	Если ПолученныеФайлы = Неопределено
	 Или ПолученныеФайлы.Количество() = 0 Тогда
		
		Возврат;
	КонецЕсли;
	
	ПоказатьОповещениеПользователя(НСтр("ru = 'Электронная подпись сохранена в файл:'"),,
		ПолученныеФайлы[0].Имя);
	
КонецПроцедуры

// Параметры записи сертификата.
// 
// Возвращаемое значение:
//  Структура - параметры оповещения при записи сертификата и изменении статуса заявления:
//   * ЭтоНовый - Булево - добавление сертификата в справочник.
//   * Установлен - Булево - сертификат установлен в личное хранилище.
//   * Отозван - Булево - сертификат помечен как отозванный.
//
Функция ПараметрыОповещенияПриЗаписиСертификата() Экспорт
	
	ПараметрыОповещенияПриЗаписиСертификата = Новый Структура;
	ПараметрыОповещенияПриЗаписиСертификата.Вставить("ЭтоНовый", Ложь);
	ПараметрыОповещенияПриЗаписиСертификата.Вставить("Установлен", Ложь);
	ПараметрыОповещенияПриЗаписиСертификата.Вставить("Отозван", Ложь);
	Возврат ПараметрыОповещенияПриЗаписиСертификата;
	
КонецФункции

// Находит сертификат на компьютере по строке отпечатка.
//
// Параметры:
//   Оповещение - ОписаниеОповещения - оповещение о результате выполнения следующих типов:
//     = СертификатКриптографии - найденный сертификат.
//     = Неопределено           - сертификат не существует в хранилище.
//     = Строка                 - текст ошибки создания менеджера криптографии (или другая ошибка).
//     = Структура              - описание ошибки в виде структуры.
//
//   Отпечаток              - Строка - Base64 кодированный отпечаток сертификата.
//   ТолькоВЛичномХранилище - Булево - если Истина, тогда искать в личном хранилище, иначе везде.
//                          - ТипХранилищаСертификатовКриптографии - указанный тип хранилища.
//
//   ПоказатьОшибку - Булево - показать ошибку создания менеджера криптографии.
//                  - Неопределено - не показывать ошибку и вернуть структуру ошибки,
//                    в том числе добавить свойство СертификатНеНайден.
//
//   Программа  - Неопределено - искать с помощью любой программы.
//              - СправочникСсылка.ПрограммыЭлектроннойПодписиИШифрования - искать
//                   с помощью указанной программы.
//              - МенеджерКриптографии - инициализированный менеджер криптографии,
//                   который нужно использовать для поиска.
//
Процедура ПолучитьСертификатПоОтпечатку(Оповещение, Отпечаток, ТолькоВЛичномХранилище,
			ПоказатьОшибку = Истина, Программа = Неопределено) Экспорт
	
	Контекст = Новый Структура;
	Контекст.Вставить("Оповещение",             Оповещение);
	Контекст.Вставить("Отпечаток",              Отпечаток);
	Контекст.Вставить("ТолькоВЛичномХранилище", ТолькоВЛичномХранилище);
	Контекст.Вставить("ПоказатьОшибку",         ПоказатьОшибку);
	
	Если ТипЗнч(Программа) = Тип("МенеджерКриптографии") Тогда
		ПолучитьСертификатПоОтпечаткуПослеСозданияМенеджераКриптографии(Программа, Контекст);
	Иначе
		
		ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
		ПараметрыСоздания.ПоказатьОшибку = ПоказатьОшибку;
		ПараметрыСоздания.Программа = Программа;
		
		СоздатьМенеджерКриптографии(Новый ОписаниеОповещения(
			"ПолучитьСертификатПоОтпечаткуПослеСозданияМенеджераКриптографии", ЭтотОбъект, Контекст),
			"ПолучениеСертификатов", ПараметрыСоздания);
		
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ПолучитьСертификатПоОтпечатку.
Процедура ПолучитьСертификатПоОтпечаткуПослеСозданияМенеджераКриптографии(Результат, Контекст) Экспорт
	
	Если ТипЗнч(Результат) <> Тип("МенеджерКриптографии") Тогда
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
		Возврат;
	КонецЕсли;
	Контекст.Вставить("МенеджерКриптографии", Результат);
	
	ТипХранилища = ЭлектроннаяПодписьСлужебныйКлиентСервер.ТипХранилищаДляПоискаСертификата(
		Контекст.ТолькоВЛичномХранилище);
	
	Попытка
		Контекст.Вставить("ДвоичныеДанныеОтпечатка", Base64Значение(Контекст.Отпечаток));
	Исключение
		Если Контекст.ПоказатьОшибку = Истина Тогда
			ВызватьИсключение;
		КонецЕсли;
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		ПредставлениеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
		ПолучитьСертификатПоОтпечаткуЗавершение(Неопределено, ПредставлениеОшибки, Контекст);
		Возврат;
	КонецПопытки;
	
	Контекст.МенеджерКриптографии.НачатьПолучениеХранилищаСертификатов(
		Новый ОписаниеОповещения(
			"ПолучитьСертификатПоОтпечаткуПослеПолученияХранилища", ЭтотОбъект, Контекст,
			"ПолучитьСертификатПоОтпечаткуПослеОшибкиПолученияХранилища", ЭтотОбъект),
		ТипХранилища);
	
КонецПроцедуры

// Продолжение процедуры ПолучитьСертификатПоОтпечатку.
Процедура ПолучитьСертификатПоОтпечаткуПослеОшибкиПолученияХранилища(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
	
	Если Контекст.ПоказатьОшибку = Истина Тогда
		Возврат;
	КонецЕсли;
	
	СтандартнаяОбработка = Ложь;
	
	ПредставлениеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
	ПолучитьСертификатПоОтпечаткуЗавершение(Неопределено, ПредставлениеОшибки, Контекст);
	
КонецПроцедуры

// Продолжение процедуры ПолучитьСертификатПоОтпечатку.
Процедура ПолучитьСертификатПоОтпечаткуПослеПолученияХранилища(ХранилищеСертификатовКриптографии, Контекст) Экспорт
	
	ХранилищеСертификатовКриптографии.НачатьПоискПоОтпечатку(Новый ОписаниеОповещения(
			"ПолучитьСертификатПоОтпечаткуПослеПоиска", ЭтотОбъект, Контекст,
			"ПолучитьСертификатПоОтпечаткуПослеОшибкиПоиска", ЭтотОбъект),
		Контекст.ДвоичныеДанныеОтпечатка);
	
КонецПроцедуры

// Продолжение процедуры ПолучитьСертификатПоОтпечатку.
Процедура ПолучитьСертификатПоОтпечаткуПослеОшибкиПоиска(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
	
	Если Контекст.ПоказатьОшибку = Истина Тогда
		Возврат;
	КонецЕсли;
	
	СтандартнаяОбработка = Ложь;
	
	ПредставлениеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
	
	ПолучитьСертификатПоОтпечаткуЗавершение(Неопределено, ПредставлениеОшибки, Контекст);
	
КонецПроцедуры

// Продолжение процедуры ПолучитьСертификатПоОтпечатку.
Процедура ПолучитьСертификатПоОтпечаткуПослеПоиска(Сертификат, Контекст) Экспорт
	
	ПолучитьСертификатПоОтпечаткуЗавершение(Сертификат, "", Контекст);
	
КонецПроцедуры

// Продолжение процедуры ПолучитьСертификатПоОтпечатку.
Процедура ПолучитьСертификатПоОтпечаткуЗавершение(Сертификат, ПредставлениеОшибки, Контекст)
	
	Если ТипЗнч(Сертификат) = Тип("СертификатКриптографии") Тогда
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Сертификат);
		Возврат;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ПредставлениеОшибки) Тогда
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Сертификат не установлен на компьютере по причине:
			           |%1'"),
			ПредставлениеОшибки);
	Иначе
		ТекстОшибки = НСтр("ru = 'Сертификат не установлен на компьютере.'");
	КонецЕсли;
	
	Если Контекст.ПоказатьОшибку = Неопределено Тогда
		Результат = Новый Структура;
		Результат.Вставить("ОписаниеОшибки", ТекстОшибки);
		Если Не ЗначениеЗаполнено(ПредставлениеОшибки) Тогда
			Результат.Вставить("СертификатНеНайден");
		КонецЕсли;
	ИначеЕсли Не ЗначениеЗаполнено(ПредставлениеОшибки) Тогда
		Результат = Неопределено;
	Иначе
		Результат = ПредставлениеОшибки;
	КонецЕсли;
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
	
КонецПроцедуры

// Получает отпечатки сертификатов пользователя ОС на компьютере.
//
// Параметры:
//  Оповещение     - ОписаниеОповещения - вызывается для передачи возвращаемого значения одного из типов:
//                     = Соответствие - Ключ - отпечаток в формате строки Base64, а Значение - Истина,
//                     = Строка - текст ошибки создания менеджера криптографии (или другая ошибка).
//
//  ТолькоЛичные   - Булево - если Ложь, то к личным сертификатам добавляются сертификаты получателей.
//
//  ПоказатьОшибку - Булево - показать ошибку создания менеджера криптографии.
//
Процедура ПолучитьОтпечаткиСертификатов(Оповещение, ТолькоЛичные, ПоказатьОшибку = Истина) Экспорт
	
	Контекст = Новый Структура;
	Контекст.Вставить("Оповещение",     Оповещение);
	Контекст.Вставить("ТолькоЛичные",   ТолькоЛичные);
	Контекст.Вставить("ПоказатьОшибку", ПоказатьОшибку = Истина);
	
	ПолучитьСвойстваСертификатовНаКлиенте(Новый ОписаниеОповещения(
			"ПолучитьОтпечаткиСертификатовПослеВыполнения", ЭтотОбъект, Контекст),
		ТолькоЛичные, Ложь, Истина, ПоказатьОшибку);
	
КонецПроцедуры

// Продолжение процедуры ПолучитьОтпечаткиСертификатов.
Процедура ПолучитьОтпечаткиСертификатовПослеВыполнения(Результат, Контекст) Экспорт
	
	Если ЗначениеЗаполнено(Результат.ОшибкаПолученияСертификатовНаКлиенте) Тогда
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат.ОшибкаПолученияСертификатовНаКлиенте);
		Возврат;
	КонецЕсли;
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат.СвойстваСертификатовНаКлиенте);
	
КонецПроцедуры

// Только для внутреннего использования.
Функция ДобавкаВремени() Экспорт
	
	Возврат ОбщегоНазначенияКлиент.ДатаСеанса() - ОбщегоНазначенияКлиент.ДатаУниверсальная();
	
КонецФункции

// Продолжение процедуры ЭлектроннаяПодписьКлиент.ПроверитьПодпись
//
// Параметры:
//   Оповещение           - см. ЭлектроннаяПодписьКлиент.ПроверитьПодпись.Оповещение
//   ИсходныеДанные       - см. ЭлектроннаяПодписьКлиент.ПроверитьПодпись.ИсходныеДанные
//   Подпись              - см. ЭлектроннаяПодписьКлиент.ПроверитьПодпись.Подпись
//   МенеджерКриптографии - см. ЭлектроннаяПодписьКлиент.ПроверитьПодпись.МенеджерКриптографии
//   НаДату               - см. ЭлектроннаяПодписьКлиент.ПроверитьПодпись.НаДату
//   ПараметрыПроверки    - см. ЭлектроннаяПодписьКлиент.ПроверитьПодпись.ПараметрыПроверки
//
Процедура ПроверитьПодпись(Оповещение, ИсходныеДанные, Подпись, МенеджерКриптографии = Неопределено, НаДату = Неопределено, ПараметрыПроверки = Неопределено) Экспорт
	
	ПараметрыДляПроверки = ЭлектроннаяПодписьКлиент.ПараметрыПроверкиПодписи();
	
	Если ПараметрыПроверки = Неопределено Тогда
		ПараметрыДляПроверки.ПоказатьОшибкуСозданияМенеджераКриптографии = Истина;
	ИначеЕсли ТипЗнч(ПараметрыПроверки) = Тип("Булево") Тогда
		ПараметрыДляПроверки.ПоказатьОшибкуСозданияМенеджераКриптографии = ПараметрыПроверки;
	ИначеЕсли ТипЗнч(ПараметрыПроверки) = Тип("Структура") Тогда
		ЗаполнитьЗначенияСвойств(ПараметрыДляПроверки, ПараметрыПроверки);
	КонецЕсли;
	
	Контекст = Новый Структура;
	Контекст.Вставить("Оповещение",     Оповещение);
	Контекст.Вставить("ИсходныеДанные", ИсходныеДанные);
	Контекст.Вставить("Подпись",        Подпись);
	Контекст.Вставить("АдресПодписи",   "");
	Контекст.Вставить("НаДату",         НаДату);
	Контекст.Вставить("ПроверятьНаСервере",
		ЭлектроннаяПодписьКлиент.ПроверятьЭлектронныеПодписиНаСервере());
		
	Если ПараметрыДляПроверки.РезультатВВидеСтруктуры Тогда
		Контекст.Вставить("РезультатПроверки", ЭлектроннаяПодписьКлиентСервер.РезультатПроверкиПодписи());
	Иначе
		Контекст.Вставить("РезультатПроверки", Неопределено);
	КонецЕсли;
	
	Если ТипЗнч(Контекст.Подпись) = Тип("Строка")
	   И ЭтоАдресВременногоХранилища(Контекст.Подпись) Тогда
		
		Контекст.АдресПодписи = Контекст.Подпись;
		Контекст.Подпись = ПолучитьИзВременногоХранилища(Подпись);
	КонецЕсли;
	
	Если Не ЭлектроннаяПодписьКлиент.ПроверятьЭлектронныеПодписиНаСервере()
	   И ТипЗнч(Контекст.ИсходныеДанные) = Тип("Строка")
	   И ЭтоАдресВременногоХранилища(Контекст.ИсходныеДанные) Тогда
		
		Контекст.ИсходныеДанные = ПолучитьИзВременногоХранилища(Контекст.ИсходныеДанные);
	КонецЕсли;
	
	Если ТипЗнч(Контекст.ИсходныеДанные) = Тип("Структура")
	   И Контекст.ИсходныеДанные.Свойство("ПараметрыXMLDSig") Тогда // ЭтоXMLDSig.
		
		Если Не Контекст.ИсходныеДанные.Свойство("КонвертXML") Тогда
			Контекст.ИсходныеДанные = Новый Структура(Новый ФиксированнаяСтруктура(Контекст.ИсходныеДанные));
			Контекст.ИсходныеДанные.Вставить("КонвертXML", Контекст.ИсходныеДанные.КонвертSOAP);
		КонецЕсли;
		СвойстваКонвертаXML = ЭлектроннаяПодписьСлужебныйВызовСервера.СвойстваКонвертаXML(
			Контекст.ИсходныеДанные.КонвертXML, Контекст.ИсходныеДанные.ПараметрыXMLDSig, Истина);
		Контекст.Вставить("СвойстваКонвертаXML", СвойстваКонвертаXML);
		Если СвойстваКонвертаXML = Неопределено Тогда
			ДанныеСертификата = ЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатИзКонвертаSOAP(
				Контекст.ИсходныеДанные.КонвертXML, Ложь);
		ИначеЕсли ЗначениеЗаполнено(СвойстваКонвертаXML.ТекстОшибки) Тогда
			ВыполнитьОбработкуОповещения(Контекст.Оповещение,
				РезультатПроверкиПодписи(СвойстваКонвертаXML.ТекстОшибки, Контекст.РезультатПроверки));
			Возврат;
		Иначе
			ДанныеСертификата = Base64Значение(СвойстваКонвертаXML.Сертификат.ЗначениеСертификата);
		КонецЕсли;
		
		Контекст.Вставить("АлгоритмПодписи",
			ЭлектроннаяПодписьСлужебныйКлиентСервер.АлгоритмПодписиСертификата(ДанныеСертификата));
		
	ИначеЕсли ТипЗнч(Контекст.Подпись) = Тип("ДвоичныеДанные") Тогда
		Контекст.Вставить("АлгоритмПодписи",
			ЭлектроннаяПодписьСлужебныйКлиентСервер.АлгоритмСформированнойПодписи(Контекст.Подпись));
	Иначе
		Контекст.Вставить("АлгоритмПодписи", "");
	КонецЕсли;
	
	Если МенеджерКриптографии = Неопределено Тогда
		
		ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
		ПараметрыСоздания.ПоказатьОшибку = ПараметрыДляПроверки.ПоказатьОшибкуСозданияМенеджераКриптографии
			И Не Контекст.ПроверятьНаСервере
			И Не ИспользоватьЭлектроннуюПодписьВМоделиСервиса()
			И Не ПроверятьСертификатыОблачнойПодписью();
		ПараметрыСоздания.АлгоритмПодписи = Контекст.АлгоритмПодписи;
		
		СоздатьМенеджерКриптографии(Новый ОписаниеОповещения(
			"ПроверитьПодписьПослеСозданияМенеджераКриптографии", ЭтотОбъект, Контекст),
			"ПроверкаПодписи", ПараметрыСоздания);
	Иначе
		ПроверитьПодписьПослеСозданияМенеджераКриптографии(МенеджерКриптографии, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ПроверитьПодпись.
Процедура ПроверитьПодписьПослеСозданияМенеджераКриптографии(Результат, Контекст) Экспорт
	
	Если Результат = "СервисКриптографии" Тогда
		ПроверитьПодписьВМоделиСервиса(Контекст);
		Возврат;
	ИначеЕсли Результат = "ОблачнаяПодпись" Тогда
		ПроверитьПодписьОблачнаяПодпись(Контекст);
		Возврат;
	ИначеЕсли ТипЗнч(Результат) = Тип("МенеджерКриптографии") Тогда
		МенеджерКриптографии = Результат;
	Иначе
		МенеджерКриптографии = Неопределено;
	КонецЕсли;
	
	Контекст.Вставить("МенеджерКриптографии", МенеджерКриптографии);
	
	Если Не ЭлектроннаяПодписьКлиент.ПроверятьЭлектронныеПодписиНаСервере() Тогда
		// Проверка подписи и сертификата на стороне клиента.
		Если МенеджерКриптографии = Неопределено Тогда
			
			Если ИспользоватьЭлектроннуюПодписьВМоделиСервиса() Тогда
				ПроверитьПодписьВМоделиСервиса(Контекст);
			ИначеЕсли ПроверятьСертификатыОблачнойПодписью() Тогда
				ПроверитьПодписьОблачнаяПодпись(Контекст);
			Иначе
				ПроверитьПодписьДобавитьСвойстваПодписиВРезультат(Контекст.Подпись, Неопределено, Контекст);
			КонецЕсли;
			
			Возврат;
			
		КонецЕсли;
		
		Контекст.Вставить("ПроверитьСертификатНаКлиенте");
		ПроверитьПодписьНаКлиенте(Контекст);
		Возврат;
	КонецЕсли;
	
	Если МенеджерКриптографии <> Неопределено
	   И Не (  ТипЗнч(Контекст.ИсходныеДанные) = Тип("Строка")
	         И ЭтоАдресВременногоХранилища(Контекст.ИсходныеДанные)) Тогда
		// Математическая проверка подписи на стороне клиента для повышения производительности и
		// безопасности в случае, когда ИсходныеДанные являются результатом расшифровки секретного файла.
		
		// Сертификат проверяется и на сервере и на клиенте.
		ПроверитьПодписьНаКлиенте(Контекст);
		Возврат;
	КонецЕсли;
	
	Если ИспользоватьЭлектроннуюПодписьВМоделиСервиса() Тогда
		// Проверка подписи и сертификата в модели сервиса.
		ПроверитьПодписьВМоделиСервиса(Контекст);
	Иначе
		// Проверка подписи и сертификата на сервере.
		Если ТипЗнч(Контекст.ИсходныеДанные) = Тип("Строка")
		   И ЭтоАдресВременногоХранилища(Контекст.ИсходныеДанные) Тогда
			
			АдресИсходныхДанных = Контекст.ИсходныеДанные;
		Иначе
			Если ТипЗнч(Контекст.ИсходныеДанные) = Тип("Структура")
			   И Контекст.ИсходныеДанные.Свойство("ПараметрыCMS") Тогда
				
				Контекст.ИсходныеДанные.ПараметрыCMS.ВключениеСертификатовВПодпись =
					ВключениеСертификатовВПодписьСтрокой(
						Контекст.ИсходныеДанные.ПараметрыCMS.ВключениеСертификатовВПодпись);
			КонецЕсли;
			АдресИсходныхДанных = ПоместитьВоВременноеХранилище(Контекст.ИсходныеДанные);
		КонецЕсли;
		
		Если Не ЗначениеЗаполнено(Контекст.АдресПодписи) Тогда
			Контекст.АдресПодписи = ПоместитьВоВременноеХранилище(Контекст.Подпись);
		КонецЕсли;
		
		ОписаниеОшибки = "";
		Результат = ЭлектроннаяПодписьСлужебныйВызовСервера.ПроверитьПодпись(
			АдресИсходныхДанных, Контекст.АдресПодписи, ОписаниеОшибки, Контекст.НаДату, Контекст.РезультатПроверки);
		
		Если Результат <> Истина Тогда
			Результат = ОписаниеОшибки;
		КонецЕсли;

		ВыполнитьОбработкуОповещения(Контекст.Оповещение,
			РезультатПроверкиПодписи(Результат, Контекст.РезультатПроверки));
		
	КонецЕсли;
	
КонецПроцедуры

Асинх Процедура ПроверитьПодписьДобавитьСвойстваПодписиВРезультат(Подпись, Результат, Контекст)
	
	ТребуетсяПроверка = Неопределено;
	
	Если ТипЗнч(Контекст.РезультатПроверки) = Тип("Структура") Тогда
		
		Если Результат = Неопределено Тогда
			Контекст.РезультатПроверки.ТребуетсяПроверка = Истина;
		ИначеЕсли ТипЗнч(Результат) =  Тип("Строка") Тогда
			ОшибкаПоКлассификатору = ЭлектроннаяПодписьСлужебныйКлиентПовтИсп.ОшибкаПоКлассификатору(Результат);
			Если ОшибкаПоКлассификатору <> Неопределено Тогда
				ТребуетсяПроверка = ОшибкаПоКлассификатору.ТребуетПроверки;
			КонецЕсли;
		КонецЕсли;
		
		Если ЭлектроннаяПодписьКлиент.ОбщиеНастройки().ДоступнаУсовершенствованнаяПодпись И ТипЗнч(
			Контекст.МенеджерКриптографии) = Тип("МенеджерКриптографии") Тогда
			СвойстваПодписи = Ждать СвойстваПодписиЧтениеМенеджеромКриптографии(Подпись, Контекст.МенеджерКриптографии, Истина);
		Иначе
			СвойстваПодписи = Ждать СвойстваПодписиИзДвоичныхДанных(Подпись, Истина);
		КонецЕсли;
			
		ЗаполнитьЗначенияСвойств(Контекст.РезультатПроверки, СвойстваПодписи);
	КонецЕсли;
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение,
		РезультатПроверкиПодписи(Результат, Контекст.РезультатПроверки, ТребуетсяПроверка));
			
КонецПроцедуры

// Продолжение процедуры ПроверитьПодпись.
Процедура ПроверитьПодписьНаКлиенте(Контекст)
	
	Контекст.Вставить("ДанныеПодписи", Контекст.Подпись);
	
	ЭтоXMLDSig = (ТипЗнч(Контекст) = Тип("Структура")
	            И ТипЗнч(Контекст.ИсходныеДанные) = Тип("Структура")
	            И Контекст.ИсходныеДанные.Свойство("ПараметрыXMLDSig"));
	
	ЭтоCMS = (ТипЗнч(Контекст) = Тип("Структура")
	            И ТипЗнч(Контекст.ИсходныеДанные) = Тип("Структура")
	            И Контекст.ИсходныеДанные.Свойство("ПараметрыCMS"));
	
	Если ЭтоXMLDSig Тогда
		
		ОповещениеУспех = Новый ОписаниеОповещения(
			"ПроверитьПодписьНаКлиентеПослеПроверкиПодписиXMLDSig", ЭтотОбъект, Контекст);
		
		ОповещениеОшибка = Новый ОписаниеОповещения(
			"ПроверитьПодписьНаКлиентеПослеОшибкиПроверкиПодписиXMLDSig", ЭтотОбъект, Контекст);
		
		Оповещения = Новый Структура;
		Оповещения.Вставить("Успех", ОповещениеУспех);
		Оповещения.Вставить("Ошибка", ОповещениеОшибка);
		
		НачатьИнициализациюСертификатаКриптографииДляПроверкиПодписиXMLDSig(Оповещения,
			Контекст.ИсходныеДанные.КонвертXML,
			Контекст.ИсходныеДанные.ПараметрыXMLDSig,
			Контекст.СвойстваКонвертаXML,
			Контекст.МенеджерКриптографии);
		
	ИначеЕсли ЭтоCMS Тогда
		
		ОповещениеУспех = Новый ОписаниеОповещения(
			"ПроверитьПодписьНаКлиентеПослеПроверкиПодписиXMLDSig", ЭтотОбъект, Контекст);
		
		ОповещениеОшибка = Новый ОписаниеОповещения(
			"ПроверитьПодписьНаКлиентеПослеОшибкиПроверкиПодписиXMLDSig", ЭтотОбъект, Контекст);
		
		Оповещения = Новый Структура;
		Оповещения.Вставить("Успех", ОповещениеУспех);
		Оповещения.Вставить("Ошибка", ОповещениеОшибка);
		
		НачатьИнициализациюСертификатаКриптографииДляПроверкиПодписиCMS(
			Оповещения,
			Контекст.ДанныеПодписи,
			Контекст.ИсходныеДанные.Данные,
			Контекст.ИсходныеДанные.ПараметрыCMS,
			Контекст.МенеджерКриптографии);
		
	Иначе
		МенеджерКриптографии = Контекст.МенеджерКриптографии; // МенеджерКриптографии
		МенеджерКриптографии.НачатьПроверкуПодписи(Новый ОписаниеОповещения(
			"ПроверитьПодписьНаКлиентеПослеПроверкиПодписи", ЭтотОбъект, Контекст,
			"ПроверитьПодписьНаКлиентеПослеОшибкиПроверкиПодписи", ЭтотОбъект),
			Контекст.ИсходныеДанные, Контекст.ДанныеПодписи);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ПроверитьПодпись.
Процедура ПроверитьПодписьНаКлиентеПослеОшибкиПроверкиПодписиXMLDSig(ТекстОшибки, Контекст) Экспорт
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, ТекстОшибки);
	
КонецПроцедуры

// Продолжение процедуры ПроверитьПодпись.
Процедура ПроверитьПодписьНаКлиентеПослеПроверкиПодписиXMLDSig(Данные, Контекст) Экспорт
	
	Если Контекст.Свойство("ПроверитьСертификатНаКлиенте") Тогда
		МенеджерКриптографии = Контекст.МенеджерКриптографии;
	Иначе
		// Проверка сертификата на сервере и на клиенте.
		МенеджерКриптографии = Неопределено;
	КонецЕсли;
	
	ДополнительныеПараметры = ДополнительныеПараметрыПроверкиСертификата();
	ДополнительныеПараметры.ДляПроверкиПодписи = Истина;
	
	Оповещение = Новый ОписаниеОповещения("ПроверитьПодписьПослеПроверкиСертификатаПодписи", ЭтотОбъект, Контекст);
		
	ПроверитьСертификат(Оповещение, Данные.Сертификат, МенеджерКриптографии, Данные.ДатаПодписания, ДополнительныеПараметры);
	
КонецПроцедуры

// Продолжение процедуры ПроверитьПодпись.
Процедура ПроверитьПодписьНаКлиентеПослеОшибкиПроверкиПодписи(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
	
	СтандартнаяОбработка = Ложь;
	
	ТекстОшибки = ?(ТипЗнч(ИнформацияОбОшибке) = Тип("ИнформацияОбОшибке"),
		ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке), Строка(ИнформацияОбОшибке));
	
	Если Контекст.Свойство("ДанныеПодписи") Тогда
		Подпись = Контекст.ДанныеПодписи;
	Иначе
		Подпись = Контекст.Подпись;
	КонецЕсли;
	
	ПроверитьПодписьДобавитьСвойстваПодписиВРезультат(Подпись, ТекстОшибки, Контекст)
	
КонецПроцедуры

// Продолжение процедуры ПроверитьПодпись.
Асинх Процедура ПроверитьПодписьНаКлиентеПослеПроверкиПодписи(Сертификат, Контекст) Экспорт
	
	Если ТипЗнч(Контекст.МенеджерКриптографии) = Тип("МенеджерКриптографии") Тогда
		
		Если ЭлектроннаяПодписьКлиент.ОбщиеНастройки().ДоступнаУсовершенствованнаяПодпись Тогда
			СвойстваПодписи = Ждать СвойстваПодписиЧтениеМенеджеромКриптографии(Контекст.ДанныеПодписи, Контекст.МенеджерКриптографии, Ложь);
		Иначе
			СвойстваПодписи = Ждать СвойстваПодписиИзДвоичныхДанных(Контекст.ДанныеПодписи, Ложь);
			СвойстваСертификата = Ждать СвойстваСертификата(Сертификат);
			СвойстваПодписи.Отпечаток = СвойстваСертификата.Отпечаток;
			СвойстваПодписи.КомуВыданСертификат = СвойстваСертификата.КомуВыдан;
		КонецЕсли;
		
		Если ТипЗнч(Контекст.РезультатПроверки) = Тип("Структура") Тогда
			ЗаполнитьЗначенияСвойств(Контекст.РезультатПроверки, СвойстваПодписи);
			Контекст.РезультатПроверки.Сертификат = Ждать Сертификат.ВыгрузитьАсинх();
		КонецЕсли;
	
	Иначе // после проверки в облачных сервисах.
		
		СвойстваПодписи = Ждать СвойстваПодписиИзДвоичныхДанных(Контекст.ДанныеПодписи, Истина);
		
		Если СвойстваПодписи.Сертификат = Неопределено Тогда
			ВыполнитьОбработкуОповещения(Контекст.Оповещение, РезультатПроверкиПодписи(
				НСтр("ru = 'Сертификат не существует в данных подписи.'"), Контекст.РезультатПроверки));
			Возврат;
		КонецЕсли;
		
		Сертификат = СвойстваПодписи.Сертификат;
		
		Если ТипЗнч(Контекст.РезультатПроверки) = Тип("Структура") Тогда
			ЗаполнитьЗначенияСвойств(Контекст.РезультатПроверки, СвойстваПодписи);
			Контекст.РезультатПроверки.Сертификат = Сертификат;
		КонецЕсли;
		
	КонецЕсли;
	
	Если Не Контекст.Свойство("ПроверитьСертификатНаКлиенте") Тогда
		// Проверка сертификата на сервере и на клиенте.
		Контекст.Вставить("МенеджерКриптографии", Неопределено);
	КонецЕсли;
		
	Контекст.Вставить("Сертификат", Сертификат);
	
	ДатаПодписания = ЭлектроннаяПодписьСлужебныйКлиентСервер.ДатаДляПроверкиСертификатаПодписи(СвойстваПодписи);
	Если Не ЗначениеЗаполнено(ДатаПодписания) Тогда
		ДатаПодписания = Контекст.НаДату;
	КонецЕсли;
	
	ДополнительныеПараметры = ДополнительныеПараметрыПроверкиСертификата();
	ДополнительныеПараметры.ДляПроверкиПодписи = Истина;
	
	Оповещение = Новый ОписаниеОповещения("ПроверитьПодписьПослеПроверкиСертификатаПодписи", ЭтотОбъект, Контекст);
	ПроверитьСертификат(Оповещение, Контекст.Сертификат, Контекст.МенеджерКриптографии, ДатаПодписания, ДополнительныеПараметры);
		
КонецПроцедуры

Процедура ПроверитьПодписьПослеПроверкиСертификатаПодписи(РезультатПроверки, Контекст) Экспорт
	
	Если ТипЗнч(РезультатПроверки) = Тип("Структура") Тогда

		Результат = РезультатПроверки.ОбщееОписаниеОшибки;
		Если Контекст.РезультатПроверки <> Неопределено Тогда
			Если РезультатПроверки.СертификатОтозван Тогда
				Результат = ЭлектроннаяПодписьСлужебныйКлиентСервер.ТекстОшибкиДляОтозванногоСертификатаПодписи(
					Контекст.РезультатПроверки);
			КонецЕсли;
			Контекст.РезультатПроверки.СертификатОтозван = РезультатПроверки.СертификатОтозван;
			Контекст.РезультатПроверки.ТребуетсяПроверка = РезультатПроверки.ТребуетсяПроверка;
		КонецЕсли;

	ИначеЕсли РезультатПроверки = Неопределено Тогда
		
		Результат = РезультатПроверки;
		Если Контекст.РезультатПроверки <> Неопределено Тогда
			Контекст.РезультатПроверки.ТребуетсяПроверка = Истина;
		КонецЕсли;
		
	Иначе
		
		Результат = РезультатПроверки;
		
	КонецЕсли;
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение,
		РезультатПроверкиПодписи(Результат, Контекст.РезультатПроверки));
	
КонецПроцедуры

// Проверяет действительность сертификата криптографии.
//
// Параметры:
//   Оповещение           - ОписаниеОповещения - оповещение о результате выполнения следующих типов:
//             = Булево       - Истина, если проверка выполнена успешно.
//             = Строка       - описание ошибки проверки сертификата.
//             = Неопределено - не удалось получить менеджер криптографии (когда не указан).
//             = Структура    - в случае ошибки, если ДополнительныеПараметры.ДляПроверкиПодписи И ДополнительныеПараметры.ОбъединитьОшибкиДанныхСертификата 
//                # ОбщееОписаниеОшибки - Строка
//                # СертификатОтозван - Булево - ошибка связана с тем, что сертификат отозван в удостоверяющем центре.
//                # ТребуетсяПроверка - Булево - ошибка требует перепроверки подписи после дополнительных действий,
//                    например, установки корневого сертификата.
//             = Структура    - в случае ошибки, если ДополнительныеПараметры.ДляПроверкиПодписи И Не ДополнительныеПараметры.ОбъединитьОшибкиДанныхСертификата 
//                # ОписаниеОшибкиНаКлиенте - Строка
//                # ОписаниеОшибкиНаСервере - Строка
//                # ДополнительныеДанныеПроверкиНаСервере - см. ЭлектроннаяПодписьСлужебныйКлиентСервер.ПредупреждениеПриПроверкеУдостоверяющегоЦентраСертификата
//                # ДополнительныеДанныеПроверкиНаКлиенте - см. ЭлектроннаяПодписьСлужебныйКлиентСервер.ПредупреждениеПриПроверкеУдостоверяющегоЦентраСертификата
//                # СертификатОтозван - Булево - см. выше.
//                # ТребуетсяПроверка - Булево - см. выше.
//
//   Сертификат           - СертификатКриптографии - сертификат.
//                        - ДвоичныеДанные - двоичные данные сертификата.
//                        - Строка - адрес временного хранилища, содержащего двоичные данные сертификата.
//
//   МенеджерКриптографии - Неопределено - получить менеджер криптографии автоматически.
//                        - МенеджерКриптографии - использовать указанный менеджер криптографии
//                          (проверка на сервере не будет выполнена).
//
//   НаДату               - Дата - проверить сертификат на указанную дату.
//                          Если параметр не указан или указана пустая дата, тогда проверять на текущую.
//
//   ДополнительныеПараметры - см. ДополнительныеПараметрыПроверкиСертификата.
//
Процедура ПроверитьСертификат(Оповещение, Сертификат, МенеджерКриптографии = Неопределено, НаДату = Неопределено,
	ДополнительныеПараметры = Неопределено) Экспорт

	Контекст = КонтекстПроверкиСертификата();
	Контекст.Оповещение =                        Оповещение;
	Контекст.Сертификат =                        Сертификат;
	Контекст.МенеджерКриптографии =              МенеджерКриптографии;
	Контекст.НаДату =                            НаДату;
	
	Если ДополнительныеПараметры <> Неопределено Тогда
		Контекст.ПоказатьОшибку                    = ДополнительныеПараметры.ПоказатьОшибку;
		Контекст.ОбъединитьОшибкиДанныхСертификата = ДополнительныеПараметры.ОбъединитьОшибкиДанныхСертификата;
		Контекст.ПроверитьВСервисеПослеОшибки      = ДополнительныеПараметры.ПроверитьВСервисеПослеОшибки;
		Контекст.ВыполнятьПроверкуУдостоверяющегоЦентра   = ДополнительныеПараметры.ВыполнятьПроверкуУдостоверяющегоЦентра;
		Контекст.ДляПроверкиПодписи                = ДополнительныеПараметры.ДляПроверкиПодписи;
	КонецЕсли;
	
	Контекст.ОписаниеОшибкиНаКлиенте = Неопределено;
	Контекст.ОписаниеОшибкиНаСервере = Неопределено;
	
	Если Контекст.МенеджерКриптографии = Неопределено И ЭлектроннаяПодписьКлиент.ПроверятьЭлектронныеПодписиНаСервере() Тогда
		
		Контекст.ТребуетПроверкиНаСервере = Ложь;
		
		// Проверка на сервере перед проверкой на клиенте.
		Если ТипЗнч(Сертификат) = Тип("СертификатКриптографии") Тогда

			Сертификат.НачатьВыгрузку(Новый ОписаниеОповещения("ПроверитьСертификатПослеВыгрузкиСертификата",
				ЭтотОбъект, Контекст));
		Иначе
			ПроверитьСертификатПослеВыгрузкиСертификата(Сертификат, Контекст);
		КонецЕсли;
	Иначе
		// Когда менеджер криптографии указан, тогда проверка выполняется только на клиенте.
		ПроверитьСертификатНаКлиенте(Контекст);
	КонецЕсли;

КонецПроцедуры

// Возвращаемое значение:
//   Структура:
//   * ОписаниеОшибкиНаСервере - Строка
//   * ОписаниеОшибкиНаКлиенте - Строка
//   * ТребуетПроверкиНаКлиенте - Неопределено, Булево
//   * ТребуетПроверкиНаСервере - Неопределено, Булево
//   * СертификатОтозван - Булево
//   * ПоказатьОшибку  - см. ПроверитьСертификат.ПоказатьОшибку
//   * НаДату - см. ПроверитьСертификат.НаДату 
//   * МенеджерКриптографии - см. ПроверитьСертификат.МенеджерКриптографии
//   * Сертификат - см. ПроверитьСертификат.Сертификат
//   * Оповещение - см. ПроверитьСертификат.Оповещение
//   * ОбъединитьОшибкиДанныхСертификата - Булево
//   * ПроверитьВСервисеПослеОшибки - Булево
//
Функция КонтекстПроверкиСертификата()
	
	Контекст = Новый Структура;
	Контекст.Вставить("Оповещение");
	Контекст.Вставить("Сертификат");
	Контекст.Вставить("СертификатОтозван", Ложь);
	Контекст.Вставить("МенеджерКриптографии");
	Контекст.Вставить("НаДату");
	Контекст.Вставить("ОписаниеОшибкиНаКлиенте");
	Контекст.Вставить("ТребуетПроверкиНаКлиенте");
	Контекст.Вставить("ДополнительныеДанныеПроверкиНаКлиенте");
	Контекст.Вставить("ОписаниеОшибкиНаСервере");
	Контекст.Вставить("ТребуетПроверкиНаСервере");
	Контекст.Вставить("ДополнительныеДанныеПроверкиНаСервере");
	Контекст.Вставить("ПоказатьОшибку", Истина);
	Контекст.Вставить("ОбъединитьОшибкиДанныхСертификата", Истина);
	Контекст.Вставить("ПроверитьВСервисеПослеОшибки", Истина);
	Контекст.Вставить("ВыполнятьПроверкуУдостоверяющегоЦентра", Истина);
	Контекст.Вставить("ДляПроверкиПодписи", Ложь);
	Контекст.Вставить("ДействияДляУстраненияОшибок", Новый Соответствие);
	Контекст.Вставить("СвойстваСертификата");
		
	Возврат Контекст;
	
КонецФункции

// Дополнительные параметры проверки сертификата.
// 
// Возвращаемое значение:
//  Структура - дополнительные параметры проверки сертификата:
//   * ПоказатьОшибку - Булево  - показать ошибку создания менеджера криптографии (когда не указан).
//   * ОбъединитьОшибкиДанныхСертификата - Булево - объединить ошибки проверки данных сертификата на клиенте и сервере в
//                                                  строку.
//   * ПроверитьВСервисеПослеОшибки - Булево - в случае ошибки при проверке данных сертификата на клиенте, проверить в сервисе.
//   * ВыполнятьПроверкуУдостоверяющегоЦентра - Булево - проверять юридическую значимость в зависимости от издателя.
//   * ДляПроверкиПодписи - Булево - не показывать оповещения для сертификатов, возвращать результат,
//                                               как указано в вызывающей процедуре проверки подписи.
//
Функция ДополнительныеПараметрыПроверкиСертификата() Экспорт
	
	Структура = Новый Структура;
	Структура.Вставить("ПоказатьОшибку", Истина);
	Структура.Вставить("ОбъединитьОшибкиДанныхСертификата", Истина);
	Структура.Вставить("ПроверитьВСервисеПослеОшибки", Истина);
	Структура.Вставить("ВыполнятьПроверкуУдостоверяющегоЦентра", Истина);
	Структура.Вставить("ДляПроверкиПодписи", Ложь);
	
	Возврат Структура;
	
КонецФункции

// Продолжение процедуры ПроверитьСертификат.
Процедура ПроверитьСертификатПослеВыгрузкиСертификата(Сертификат, Контекст) Экспорт
	
	// Проверка сертификата на сервере.
	Если ТипЗнч(Сертификат) = Тип("ДвоичныеДанные") Тогда
		АдресСертификата = ПоместитьВоВременноеХранилище(Сертификат);
	Иначе
		АдресСертификата = Сертификат;
	КонецЕсли;
	
	ДополнительныеПараметры = Новый Структура;
	ДополнительныеПараметры.Вставить("ВыполнятьПроверкуУдостоверяющегоЦентра", Контекст.ВыполнятьПроверкуУдостоверяющегоЦентра);
	ДополнительныеПараметры.Вставить("ДляПроверкиПодписи", Контекст.ДляПроверкиПодписи);
	ДополнительныеПараметры.Вставить("Предупреждение");
	ДополнительныеПараметры.Вставить("Сертификат");
	
	Если ЭлектроннаяПодписьСлужебныйВызовСервера.ПроверитьСертификат(АдресСертификата,
		Контекст.ОписаниеОшибкиНаСервере, Контекст.НаДату, ДополнительныеПараметры) Тогда

		Если ЗначениеЗаполнено(ДополнительныеПараметры.Предупреждение) И Не Контекст.ДляПроверкиПодписи
			И ДополнительныеПараметры.Сертификат <> Неопределено Тогда

			ПараметрыОткрытияФормы = Новый Структура("Сертификат, ДополнительныеДанныеПроверки", ДополнительныеПараметры.Сертификат,
				ДополнительныеПараметры.Предупреждение);
			ДействиеПриНажатии = Новый ОписаниеОповещения("ОткрытьФормуОповещенияОНеобходимостиЗаменыСертификата",
				ЭлектроннаяПодписьСлужебныйКлиент, ПараметрыОткрытияФормы);

			ПоказатьОповещениеПользователя(
					НСтр("ru = 'Необходима замена сертификата'"), ДействиеПриНажатии, ДополнительныеПараметры.Сертификат,
				БиблиотекаКартинок.Предупреждение32, СтатусОповещенияПользователя.Важное, ДополнительныеПараметры.Сертификат);

		КонецЕсли;

		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Истина);
	Иначе
		ПроверитьСертификатНаКлиенте(Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ПроверитьСертификат.
Процедура ПроверитьСертификатНаКлиенте(Контекст)
	
	Контекст.ТребуетПроверкиНаКлиенте = Ложь;
	
	СертификатДляПроверки = Контекст.Сертификат;
	
	Если ТипЗнч(СертификатДляПроверки) = Тип("Строка") Тогда
		СертификатДляПроверки = ПолучитьИзВременногоХранилища(СертификатДляПроверки);
	КонецЕсли;
	Контекст.Вставить("СертификатДляПроверки", СертификатДляПроверки);
	
	Если ТипЗнч(СертификатДляПроверки) = Тип("ДвоичныеДанные") Тогда
		
		ЭлектроннаяПодписьКлиент.УстановитьРасширение(Ложь, Новый ОписаниеОповещения(
			"ПроверитьСертификатНаКлиентеПослеПодключенияРасширенияРаботыСКриптографией", ЭтотОбъект, Контекст),
			НСтр("ru = 'Для продолжения установите расширение для работы с криптографией.'"));
	
	Иначе
		ПроверитьСертификатПослеИнициализацииСертификата(СертификатДляПроверки, Контекст)
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ПроверитьСертификат.
Процедура ПроверитьСертификатНаКлиентеПослеПодключенияРасширенияРаботыСКриптографией(Подключено, Контекст) Экспорт
	
	Если Подключено = Истина Тогда
		СертификатКриптографии = Новый СертификатКриптографии;
		СертификатКриптографии.НачатьИнициализацию(Новый ОписаниеОповещения(
				"ПроверитьСертификатПослеИнициализацииСертификата", ЭтотОбъект, Контекст),
			Контекст.СертификатДляПроверки);
	Иначе
		ПроверитьСертификатНаКлиентеПослеОшибкиПроверки(
			НСтр("ru = 'Не установлено расширение для работы с криптографией.'"), Ложь, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ПроверитьСертификат.
Процедура ПроверитьСертификатПослеИнициализацииСертификата(СертификатКриптографии, Контекст) Экспорт
	
	Контекст.Вставить("СертификатКриптографии", СертификатКриптографии);
	Контекст.Вставить("РежимыПроверкиСертификата",
		ЭлектроннаяПодписьСлужебныйКлиентСервер.РежимыПроверкиСертификата(
			ЗначениеЗаполнено(Контекст.НаДату)));
	
	Если ТипЗнч(Контекст.СертификатДляПроверки) = Тип("СертификатКриптографии") Тогда
		Контекст.СертификатДляПроверки.НачатьВыгрузку(Новый ОписаниеОповещения(
			"ПроверитьСертификатПослеОпределенияАлгоритмаПодписания", ЭтотОбъект, Контекст));
	Иначе
		ПроверитьСертификатПослеОпределенияАлгоритмаПодписания(Контекст.СертификатДляПроверки, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ПроверитьСертификат.
Процедура ПроверитьСертификатПослеОпределенияАлгоритмаПодписания(ДанныеСертификата, Контекст) Экспорт
	
	Контекст.Вставить("ДанныеСертификата", ДанныеСертификата);
	Контекст.Вставить("АлгоритмПодписи",
		ЭлектроннаяПодписьСлужебныйКлиентСервер.АлгоритмПодписиСертификата(ДанныеСертификата));
		
	ПродолжитьПроверкуСертификатаНаКлиенте(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ПроверитьСертификат.
Процедура ПродолжитьПроверкуСертификатаНаКлиенте(Контекст)
	
	Если Контекст.МенеджерКриптографии = Неопределено Тогда
		
		ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
		Если Контекст.ПоказатьОшибку = Истина
		   И Контекст.ОписаниеОшибкиНаСервере = Неопределено
		   И Не ИспользоватьЭлектроннуюПодписьВМоделиСервиса() Тогда
			
			ПараметрыСоздания.ПоказатьОшибку = Истина;
		Иначе
			ПараметрыСоздания.ПоказатьОшибку = Неопределено;
		КонецЕсли;
		ПараметрыСоздания.АлгоритмПодписи = Контекст.АлгоритмПодписи;
		
		СоздатьМенеджерКриптографии(Новый ОписаниеОповещения(
				"ПроверитьСертификатПослеСозданияМенеджераКриптографии", ЭтотОбъект, Контекст),
			"ПроверкаСертификата", ПараметрыСоздания);
		
	Иначе
		
		Если Контекст.МенеджерКриптографии = "СервисКриптографии" Тогда
			ПроверитьСертификатВМоделиСервиса(Контекст);
		ИначеЕсли Контекст.МенеджерКриптографии = "ОблачнаяПодпись" Тогда
			ПроверитьСертификатОблачнаяПодпись(Контекст);
		Иначе
			ПроверитьСертификатПослеСозданияМенеджераКриптографии(Контекст.МенеджерКриптографии, Контекст);
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ПроверитьСертификат.
Процедура ПроверитьСертификатПослеСозданияМенеджераКриптографии(Результат, Контекст) Экспорт
	
	Если ТипЗнч(Результат) <> Тип("МенеджерКриптографии") Тогда
		Если ИспользоватьЭлектроннуюПодписьВМоделиСервиса() Тогда
			ПроверитьСертификатВМоделиСервиса(Контекст);
		ИначеЕсли ПроверятьСертификатыОблачнойПодписью() Тогда
			ПроверитьСертификатОблачнаяПодпись(Контекст);
		Иначе
			Если ТипЗнч(Результат) = Тип("Структура") Тогда
				Контекст.ОписаниеОшибкиНаКлиенте = Результат;
			КонецЕсли;
			ПроверитьСертификатПослеНеуспешнойПроверки(Контекст);
		КонецЕсли;
		Возврат;
	КонецЕсли;
	
	Контекст.МенеджерКриптографии = Результат;
	
	Контекст.МенеджерКриптографии.НачатьПроверкуСертификата(Новый ОписаниеОповещения(
		"ПроверитьСертификатНаКлиентеПослеПроверки", ЭтотОбъект, Контекст,
		"ПроверитьСертификатНаКлиентеПослеОшибкиПроверки", ЭтотОбъект),
		Контекст.СертификатКриптографии, Контекст.РежимыПроверкиСертификата);
	
КонецПроцедуры

// Продолжение процедуры ПроверитьСертификат.
Процедура ПроверитьСертификатНаКлиентеПослеОшибкиПроверки(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
	
	СтандартнаяОбработка = Ложь;
	Если ТипЗнч(ИнформацияОбОшибке) = Тип("ИнформацияОбОшибке") Тогда
		
		ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
		ОшибкаПоКлассификатору = ЭлектроннаяПодписьСлужебныйКлиентПовтИсп.ОшибкаПоКлассификатору(ОписаниеОшибки);

		// Локализация
		
		Если ОшибкаПоКлассификатору <> Неопределено И ЗначениеЗаполнено(ОшибкаПоКлассификатору.ДействияДляУстранения) Тогда
			
			Действие = Неопределено;
			
			Для Каждого ТекущееДействие Из ОшибкаПоКлассификатору.ДействияДляУстранения Цикл
				Если Контекст.ДействияДляУстраненияОшибок.Получить(ТекущееДействие) = Неопределено Тогда
					Действие = ТекущееДействие;
					Прервать;
				КонецЕсли;
			КонецЦикла;
			 
			Если Действие <> Неопределено Тогда
				Контекст.ДействияДляУстраненияОшибок.Вставить(Действие, ОписаниеОшибки);
				Контекст.ДействияДляУстраненияОшибок.Вставить("ДействиеПриПовторнойПроверке", Действие);
				
				Если Действие = "УстановитьСписокОтзываСертификата" Тогда
					ИмяИздателя = НРег(ЭлектроннаяПодписьКлиент.СвойстваИздателяСертификата(Контекст.СертификатКриптографии).ОбщееИмя);
					Если ЗначениеЗаполнено(ИмяИздателя) Тогда
						ИмяИздателя = СтроковыеФункцииКлиент.СтрокаЛатиницей(ИмяИздателя);
						АдресСпискаОтзываВнутренний = ЭлектроннаяПодписьСлужебныйКлиентСервер.АдресСпискаОтзываВнутренний(
							ИмяИздателя, Контекст.ДанныеСертификата);
						Если ЗначениеЗаполнено(АдресСпискаОтзываВнутренний.АдресВнутренний) Тогда
							ПараметрыУстановкиСпискаОтзыва = ПараметрыУстановкиСпискаОтзыва(
								Контекст.СертификатКриптографии);
							ПараметрыУстановкиСпискаОтзыва.Адреса = АдресСпискаОтзываВнутренний.АдресВнешний;
							ПараметрыУстановкиСпискаОтзыва.АдресВнутренний = АдресСпискаОтзываВнутренний.АдресВнутренний;
							ПараметрыУстановкиСпискаОтзыва.ОповещениеОЗавершении = Новый ОписаниеОповещения("ПроверитьСертификатПовторно",
								ЭтотОбъект, Контекст);
							ПараметрыУстановкиСпискаОтзыва.ТекстПояснения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
								НСтр("ru = 'Для проверки сертификата требуется установка списка отзыва с помощью внешней компоненты %1.'"),
								"ExtraCryptoAPI");
							УстановитьСписокОтзываСертификата(ПараметрыУстановкиСпискаОтзыва);
							Возврат;
						КонецЕсли;
					КонецЕсли;
				КонецЕсли;
				
			КонецЕсли;
		КонецЕсли;
		
		// Конец локализация
		
		Если ОшибкаПоКлассификатору <> Неопределено Тогда
			ОбработатьОшибкуПоКлассификатору(ОписаниеОшибки, Контекст.ТребуетПроверкиНаКлиенте, Контекст, ОшибкаПоКлассификатору);
		КонецЕсли;
		
	Иначе
		ОписаниеОшибки = Строка(ИнформацияОбОшибке);
	КонецЕсли;
	
	Контекст.ОписаниеОшибкиНаКлиенте = ОписаниеОшибки;
	
	Если Контекст.ПроверитьВСервисеПослеОшибки И ИспользоватьЭлектроннуюПодписьВМоделиСервиса() Тогда
		ПроверитьСертификатВМоделиСервиса(Контекст);
	ИначеЕсли Контекст.ПроверитьВСервисеПослеОшибки И ПроверятьСертификатыОблачнойПодписью() Тогда
		ПроверитьСертификатОблачнаяПодпись(Контекст, Ложь);
	Иначе
		ПроверитьСертификатПослеНеуспешнойПроверки(Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ПроверитьСертификат.
Процедура ПроверитьСертификатПовторно(Результат, Контекст) Экспорт
	
	Если Контекст.ДействияДляУстраненияОшибок.Получить("ДействиеПриПовторнойПроверке") = "УстановитьСписокОтзываСертификата" Тогда
		
		Если Не Результат.УстановкаВыполнена Тогда
			
			ТекстПредыдущейОшибки = Контекст.ДействияДляУстраненияОшибок.Получить("УстановитьСписокОтзываСертификата");
			ПроверитьСертификатНаКлиентеПослеОшибкиПроверки(ТекстПредыдущейОшибки, Ложь, Контекст);
			
			ТекстОшибкиУстановкиСпискаОтзыва = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось установить список отзыва при проверке сертификата: %1'"), Результат.Сообщение);
			ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(
				НСтр("ru = 'Электронная подпись.Обновление списков отзыва'", ОбщегоНазначенияКлиент.КодОсновногоЯзыка()),
				"Предупреждение", ТекстОшибкиУстановкиСпискаОтзыва,, Истина);
			
			Возврат;
		КонецЕсли;
		
	КонецЕсли;
	
	Контекст.МенеджерКриптографии.НачатьПроверкуСертификата(Новый ОписаниеОповещения(
		"ПроверитьСертификатНаКлиентеПослеПроверки", ЭтотОбъект, Контекст,
		"ПроверитьСертификатНаКлиентеПослеОшибкиПроверки", ЭтотОбъект),
		Контекст.СертификатКриптографии, Контекст.РежимыПроверкиСертификата);
	
КонецПроцедуры

// Продолжение процедуры ПроверитьСертификат.
Асинх Процедура ПроверитьСертификатНаКлиентеПослеПроверки(Контекст) Экспорт
	
	ОшибкаПросрочки = ЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатПросрочен(
		Контекст.СертификатКриптографии, Контекст.НаДату, ДобавкаВремени());
	
	Если ЗначениеЗаполнено(ОшибкаПросрочки) Тогда
		ПроверитьСертификатНаКлиентеПослеОшибкиПроверки(ОшибкаПросрочки, Ложь, Контекст);
	Иначе
		
		Если Контекст.ДляПроверкиПодписи Тогда
			СвойстваСертификата = Ждать СвойстваСертификата(Контекст.СертификатКриптографии);
			Контекст.СвойстваСертификата = СвойстваСертификата;
			ОшибкаПросрочки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ЗакрытыйКлючПросрочен(
				СвойстваСертификата, Контекст.НаДату);
			Если ЗначениеЗаполнено(ОшибкаПросрочки) Тогда
				ПроверитьСертификатНаКлиентеПослеОшибкиПроверки(ОшибкаПросрочки, Ложь, Контекст);
				Возврат;
			КонецЕсли;
		КонецЕсли;
		
		ДополнительнаяПроверкаСертификата(Контекст.СертификатКриптографии, Ложь, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ПроверитьСертификат.
Асинх Процедура ДополнительнаяПроверкаСертификата(СертификатКриптографии, ПроверкаНаСервере, Контекст)
	
	Если Контекст.ВыполнятьПроверкуУдостоверяющегоЦентра Тогда
		
		РезультатПроверкиУдостоверяющегоЦентраСертификата = Ждать РезультатПроверкиУдостоверяющегоЦентраСертификата(
			СертификатКриптографии, Контекст.НаДату, Контекст.ДляПроверкиПодписи, Контекст.СвойстваСертификата);
			
		Если Не РезультатПроверкиУдостоверяющегоЦентраСертификата.Действует Или ЗначениеЗаполнено(
			РезультатПроверкиУдостоверяющегоЦентраСертификата.Предупреждение.ТекстОшибки)
			И Не Контекст.ДляПроверкиПодписи Тогда
			
			ПользовательскиеНастройкиСертификата = ЭлектроннаяПодписьСлужебныйВызовСервера.ПользовательскиеНастройкиСертификата(
					СертификатКриптографии.Отпечаток);
			
			Если Не РезультатПроверкиУдостоверяющегоЦентраСертификата.Действует
				И ПользовательскиеНастройкиСертификата.ПодписаниеРазрешено <> Истина Тогда
			
				Если ПроверкаНаСервере Тогда
					Контекст.ОписаниеОшибкиНаСервере = РезультатПроверкиУдостоверяющегоЦентраСертификата.Предупреждение.ТекстОшибки;
					Контекст.ДополнительныеДанныеПроверкиНаСервере = РезультатПроверкиУдостоверяющегоЦентраСертификата.Предупреждение;
				Иначе
					Контекст.ОписаниеОшибкиНаКлиенте = РезультатПроверкиУдостоверяющегоЦентраСертификата.Предупреждение.ТекстОшибки;
					Контекст.ДополнительныеДанныеПроверкиНаКлиенте = РезультатПроверкиУдостоверяющегоЦентраСертификата.Предупреждение;
				КонецЕсли;

				ПроверитьСертификатПослеНеуспешнойПроверки(Контекст);
				Возврат;

			КонецЕсли;

			Если ЗначениеЗаполнено(РезультатПроверкиУдостоверяющегоЦентраСертификата.Предупреждение.ТекстОшибки)
				И Не Контекст.ДляПроверкиПодписи Тогда
				
				СсылкаНаСертификат = ПользовательскиеНастройкиСертификата.СсылкаНаСертификат;
				Если Не ПользовательскиеНастройкиСертификата.Оповещен И СсылкаНаСертификат <> Неопределено Тогда

					ПараметрыОткрытияФормы = Новый Структура("Сертификат, ДополнительныеДанныеПроверки",
						СсылкаНаСертификат, РезультатПроверкиУдостоверяющегоЦентраСертификата.Предупреждение);
					ДействиеПриНажатии = Новый ОписаниеОповещения("ОткрытьФормуОповещенияОНеобходимостиЗаменыСертификата",
						ЭлектроннаяПодписьСлужебныйКлиент, ПараметрыОткрытияФормы);

					ПоказатьОповещениеПользователя(
					НСтр("ru = 'Необходима замена сертификата'"), ДействиеПриНажатии, СсылкаНаСертификат,
						БиблиотекаКартинок.Предупреждение32, СтатусОповещенияПользователя.Важное, СсылкаНаСертификат);
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
		
	КонецЕсли;
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, Истина);
	
КонецПроцедуры

Асинх Функция РезультатПроверкиУдостоверяющегоЦентраСертификата(СертификатКриптографии,  НаДату = Неопределено, ЭтоПроверкаПодписи = Ложь, СвойстваСертификата = Неопределено) Экспорт
	
	Результат = ЭлектроннаяПодписьСлужебныйКлиентСервер.РезультатПроверкиУдостоверяющегоЦентраПоУмолчанию();
	
	// Локализация
	
	Если Не ЭлектроннаяПодписьКлиент.ОбщиеНастройки().ДоступнаПроверкаПоСпискуУЦ Тогда
		Возврат Результат;
	КонецЕсли;
	
	МодульЭлектроннаяПодписьКлиентСерверЛокализация = ОбщегоНазначенияКлиент.ОбщийМодуль(
		"ЭлектроннаяПодписьКлиентСерверЛокализация");

	ДанныеДляПроверкиУдостоверяющегоЦентра = МодульЭлектроннаяПодписьКлиентСерверЛокализация.ДанныеДляПроверкиУдостоверяющегоЦентра(
			СертификатКриптографии);

	Если ДанныеДляПроверкиУдостоверяющегоЦентра.ЗначенияПоиска = Неопределено Тогда
		Возврат Результат;
	КонецЕсли;

	ДанныеУдостоверяющегоЦентра = ЭлектроннаяПодписьСлужебныйКлиентПовтИсп.ДанныеУдостоверяющегоЦентра(
			ДанныеДляПроверкиУдостоверяющегоЦентра.ЗначенияПоиска);

	Если ДанныеУдостоверяющегоЦентра = Неопределено Тогда
		Возврат Результат;
	КонецЕсли;

	КонтекстПроверки = МодульЭлектроннаяПодписьКлиентСерверЛокализация.КонтекстПроверкиУдостоверяющегоЦентраСертификата();
	КонтекстПроверки.ДанныеУдостоверяющегоЦентра = ДанныеУдостоверяющегоЦентра;
	КонтекстПроверки.НаименованиеУдостоверяющегоЦентра = ДанныеДляПроверкиУдостоверяющегоЦентра.НаименованиеУдостоверяющегоЦентра;
	КонтекстПроверки.ЗначенияПоиска = ДанныеДляПроверкиУдостоверяющегоЦентра.ЗначенияПоиска;
	КонтекстПроверки.НаДату = ?(НаДату = Неопределено, ОбщегоНазначенияКлиент.ДатаСеанса(), НаДату);
	КонтекстПроверки.ДобавкаВремени = ДобавкаВремени();
	КонтекстПроверки.ЭтоПроверкаПодписи  = ЭтоПроверкаПодписи;
	Если СвойстваСертификата = Неопределено Тогда
		КонтекстПроверки.СвойстваСертификата = Ждать СвойстваСертификата(СертификатКриптографии);
	Иначе
		КонтекстПроверки.СвойстваСертификата = СвойстваСертификата;
	КонецЕсли;

	Результат = МодульЭлектроннаяПодписьКлиентСерверЛокализация.РезультатПроверкиУдостоверяющегоЦентраСертификата(
		СертификатКриптографии, КонтекстПроверки);

	Если ЗначениеЗаполнено(Результат.Предупреждение.Причина) Тогда
		Результат.Предупреждение.Причина = СтроковыеФункцииКлиент.ФорматированнаяСтрока(
			Результат.Предупреждение.Причина);
	КонецЕсли;

	Если ЗначениеЗаполнено(Результат.Предупреждение.Решение) Тогда
		Результат.Предупреждение.Решение = СтроковыеФункцииКлиент.ФорматированнаяСтрока(
			Результат.Предупреждение.Решение);
	КонецЕсли;
	
	// Конец Локализация

	Возврат Результат;
		
КонецФункции

// Продолжение процедуры ПроверитьСертификат.
//
// Параметры:
//   Контекст - Структура:
//     * Сертификат - СертификатКриптографии
//
Процедура ПроверитьСертификатВМоделиСервиса(Контекст)
	
	Если ТипЗнч(Контекст.Сертификат) = Тип("СертификатКриптографии") Тогда
		Контекст.Сертификат.НачатьВыгрузку(Новый ОписаниеОповещения(
			"ПроверитьСертификатВМоделиСервисаПослеВыгрузкиСертификата", ЭтотОбъект, Контекст));
	Иначе
		ПроверитьСертификатВМоделиСервисаПослеВыгрузкиСертификата(Контекст.Сертификат, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ПроверитьСертификат.
Процедура ПроверитьСертификатВМоделиСервисаПослеВыгрузкиСертификата(Сертификат, Контекст) Экспорт
	
	Если ТипЗнч(Сертификат) = Тип("ДвоичныеДанные") Тогда
		ДанныеСертификата = Сертификат;
	Иначе
		ДанныеСертификата = ПолучитьИзВременногоХранилища(Сертификат);
	КонецЕсли;
	
	МодульСервисКриптографииКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииКлиент");
	ПараметрыПроверки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ПараметрыПроверкиСертификатаВСервисе(
		ЭлектроннаяПодписьКлиент.ОбщиеНастройки(), Контекст.РежимыПроверкиСертификата);
	
	Если ПараметрыПроверки <> Неопределено Тогда
		// АПК:287-выкл - №640 - допустимо вызывать несуществующую процедуру БТС,
		// так как проверяется версия БТС 2.0.3, начиная с которой процедура существует.
		МодульСервисКриптографииКлиент.ПроверитьСертификатСПараметрами(Новый ОписаниеОповещения(
			"ПроверитьСертификатПослеПроверкиВМоделиСервиса", ЭтотОбъект, Контекст), ДанныеСертификата, ПараметрыПроверки);
		// АПК:287-вкл
	Иначе
		МодульСервисКриптографииКлиент.ПроверитьСертификат(Новый ОписаниеОповещения(
			"ПроверитьСертификатПослеПроверкиВМоделиСервиса", ЭтотОбъект, Контекст), ДанныеСертификата);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ПроверитьСертификат.
Процедура ПроверитьСертификатПослеПроверкиВМоделиСервиса(Результат, Контекст) Экспорт
	
	Если Не Результат.Выполнено Тогда
		Контекст.ОписаниеОшибкиНаСервере = ОбработкаОшибок.КраткоеПредставлениеОшибки(Результат.ИнформацияОбОшибке);
		ПроверитьСертификатПослеНеуспешнойПроверки(Контекст);
		Возврат;
	КонецЕсли;
	
	Если Не Результат.Действителен Тогда
		Контекст.ОписаниеОшибкиНаСервере =
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ТекстОшибкиСервисаСертификатНедействителен();
		ОбработатьОшибкуПоКлассификатору(Контекст.ОписаниеОшибкиНаСервере, Контекст.ТребуетПроверкиНаСервере, Контекст);
		ПроверитьСертификатПослеНеуспешнойПроверки(Контекст);
		Возврат;
	КонецЕсли;
	
	ОшибкаПросрочки = ЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатПросрочен(
		Контекст.СертификатКриптографии, Контекст.НаДату, ДобавкаВремени());
	
	Если ЗначениеЗаполнено(ОшибкаПросрочки) Тогда
		Контекст.ОписаниеОшибкиНаСервере = ОшибкаПросрочки;
		ПроверитьСертификатПослеНеуспешнойПроверки(Контекст);
		Возврат;
	КонецЕсли;
	
	ДополнительнаяПроверкаСертификата(Контекст.СертификатКриптографии, Истина, Контекст);

КонецПроцедуры

// Продолжение процедуры ПроверитьСертификат.
Процедура ПроверитьСертификатПослеНеуспешнойПроверки(Контекст)
	
	Если Контекст.ОбъединитьОшибкиДанныхСертификата Тогда
		Если Контекст.ОписаниеОшибкиНаКлиенте = Неопределено
		   И Контекст.ОписаниеОшибкиНаСервере = Неопределено Тогда
			
			ОбщееОписаниеОшибки = Неопределено;
		Иначе
			ОбщееОписаниеОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОбщееОписаниеОшибки(
				Контекст.ОписаниеОшибкиНаКлиенте, Контекст.ОписаниеОшибкиНаСервере, Неопределено);
		КонецЕсли;
	
		Если Контекст.ДляПроверкиПодписи Тогда
			
			Структура = Новый Структура;
			Структура.Вставить("ОбщееОписаниеОшибки", ОбщееОписаниеОшибки);
			Структура.Вставить("СертификатОтозван", Контекст.СертификатОтозван);
			Структура.Вставить("ТребуетсяПроверка", ОбщееОписаниеОшибки = Неопределено
				Или (Контекст.ТребуетПроверкиНаСервере = Неопределено Или Контекст.ТребуетПроверкиНаСервере)
				И (Контекст.ТребуетПроверкиНаКлиенте = Неопределено Или Контекст.ТребуетПроверкиНаКлиенте));
			
			ВыполнитьОбработкуОповещения(Контекст.Оповещение, Структура);
			
		Иначе
			ВыполнитьОбработкуОповещения(Контекст.Оповещение, ОбщееОписаниеОшибки);
		КонецЕсли;
		
	Иначе
		
		Структура = Новый Структура;
		Структура.Вставить("ОписаниеОшибкиНаКлиенте", Контекст.ОписаниеОшибкиНаКлиенте);
		Структура.Вставить("ОписаниеОшибкиНаСервере", Контекст.ОписаниеОшибкиНаСервере);
		Структура.Вставить("ДополнительныеДанныеПроверкиНаСервере", Контекст.ДополнительныеДанныеПроверкиНаСервере);
		Структура.Вставить("ДополнительныеДанныеПроверкиНаКлиенте", Контекст.ДополнительныеДанныеПроверкиНаКлиенте);
		
		Если Контекст.ДляПроверкиПодписи Тогда
			
			Структура.Вставить("СертификатОтозван", Контекст.СертификатОтозван);
			Структура.Вставить("ТребуетсяПроверка", ОбщееОписаниеОшибки = Неопределено
				Или (Контекст.ТребуетПроверкиНаСервере = Неопределено Или Контекст.ТребуетПроверкиНаСервере)
				И (Контекст.ТребуетПроверкиНаКлиенте = Неопределено Или Контекст.ТребуетПроверкиНаКлиенте));
			
			ВыполнитьОбработкуОповещения(Контекст.Оповещение, Структура);
		Иначе
			ВыполнитьОбработкуОповещения(Контекст.Оповещение, Структура);
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

// Возвращает дополнительные параметры создания менеджера криптографии.
//
// Возвращаемое значение:
//   Структура:
//     * ПоказатьОшибку - Булево - если Истина, тогда будет открыта форма ОшибкаОбращенияКПрограмме
//                      из которой можно перейти к списку установленных программ
//                      в форму персональных настроек на страницу "Установленные программы",
//                      в которой можно увидеть почему программу не удалось задействовать,
//                      а также открыть инструкцию по установке.
//                      - Неопределено - вернуть все ошибки обращения к программам (см. выше).
//
//     * Программа          - Неопределено - возвращает менеджер криптографии первой
//                          программы из справочника для которой удалось его создать.
//                          - СправочникСсылка.ПрограммыЭлектроннойПодписиИШифрования - программа
//                          для которой нужно создать и вернуть менеджер криптографии.
//                          - Структура - см. ЭлектроннаяПодпись.НовоеОписаниеПрограммы
//                          - ДвоичныеДанные - данные подписи или сертификата в кодировке DER для определения программы.
//                          - Строка - адрес двоичных данных, описанных выше, во временном хранилище.
//
//
//     * ИнтерактивныйРежим - Булево - если Истина, тогда менеджер криптографии будет создан
//                          в режиме использования интерактивного режима криптографии
//                          (установка свойства ПарольДоступаКЗакрытомуКлючу будет запрещена).
//
//     * АлгоритмПодписи    - Строка - если параметр заполнен, возвращает программу с указанным алгоритмом подписи.
//     * Автоопределение    - Булево - использовать автоопределение программ, установленных на компьютере,
//                          если программа не указана.
//
Функция ПараметрыСозданияМенеджераКриптографии() Экспорт
	
	ПараметрыСозданияМенеджераКриптографии = Новый Структура;
	ПараметрыСозданияМенеджераКриптографии.Вставить("ПоказатьОшибку", Ложь);
	ПараметрыСозданияМенеджераКриптографии.Вставить("Программа", Неопределено);
	ПараметрыСозданияМенеджераКриптографии.Вставить("ИнтерактивныйРежим", Ложь);
	ПараметрыСозданияМенеджераКриптографии.Вставить("АлгоритмПодписи", "");
	ПараметрыСозданияМенеджераКриптографии.Вставить("Автоопределение", Истина);
	
	Возврат ПараметрыСозданияМенеджераКриптографии;
	
КонецФункции

// Создает и возвращает менеджер криптографии (на клиенте) для указанной программы.
//
// Параметры:
//  Оповещение     - ОписаниеОповещения - оповещение о результате выполнения следующих типов:
//    = Строка - описание ошибки при создании менеджера криптографии.
//    = Структура - см. ЭлектроннаяПодписьСлужебныйКлиентСервер.НовоеОписаниеОшибок
//    = МенеджерКриптографии - инициализированный менеджер криптографии.
//
//  Операция       - Строка - если не пустая, то должна содержать одну из строк, которые определяют
//                   операцию для вставки в описание ошибки: Подписание, ПроверкаПодписи, Шифрование,
//                   Расшифровка, ПроверкаСертификата, ПолучениеСертификатов.
//  ПараметрыСозданияМенеджераКриптографии - см. ПараметрыСозданияМенеджераКриптографии.
//
Процедура СоздатьМенеджерКриптографии(Оповещение, Операция, ПараметрыСозданияМенеджераКриптографии = Неопределено) Экспорт
	
	Если ПараметрыСозданияМенеджераКриптографии = Неопределено Тогда
		ПараметрыСозданияМенеджераКриптографии = ПараметрыСозданияМенеджераКриптографии();
	КонецЕсли;
	
	Контекст = КонтекстСоздатьМенеджерКриптографии();
	Контекст.Операция = Операция;
	Контекст.Оповещение = Оповещение;
	Контекст.Программа =
		ПараметрыСозданияМенеджераКриптографии.Программа;
	Контекст.ПоказатьОшибку =
		ПараметрыСозданияМенеджераКриптографии.ПоказатьОшибку;
	Контекст.АлгоритмПодписи =
		ПараметрыСозданияМенеджераКриптографии.АлгоритмПодписи;
	Контекст.ИнтерактивныйРежим =
		ПараметрыСозданияМенеджераКриптографии.ИнтерактивныйРежим;
	Контекст.Автоопределение = 
		ПараметрыСозданияМенеджераКриптографии.Автоопределение;
	
	НачатьПодключениеРасширенияРаботыСКриптографией(Новый ОписаниеОповещения(
		"СоздатьМенеджерКриптографииПослеПодключенияРасширенияРаботыСКриптографией", ЭтотОбъект, Контекст));
	
КонецПроцедуры

// Возвращаемое значение:
//  Структура:
//   * ИнтерактивныйРежим - Булево
//   * АлгоритмПодписи - Строка
//   * ПоказатьОшибку - Булево
//   * Программа - СправочникСсылка.ПрограммыЭлектроннойПодписиИШифрования
//               - ДвоичныеДанные - данные подписи или сертификата в кодировке DER
//               - Строка - адрес данных, указанных выше во временном хранилище
//               - Структура - см. ЭлектроннаяПодпись.НовоеОписаниеПрограммы
//               - ФиксированнаяСтруктура - см. ЭлектроннаяПодпись.НовоеОписаниеПрограммы
//   * Оповещение - ОписаниеОповещения
//   * Операция - см. СоздатьМенеджерКриптографии.Операция
//   * Автоопределение - Булево
//   * ОписаниеПрограмм - Массив из см. ЭлектроннаяПодписьСлужебныйПовтИсп.ОписаниеПрограммы
//   * СвойстваОшибки - Массив из Структура:
//      ** Описание - Строка
//   * Индекс - Число
// 
Функция КонтекстСоздатьМенеджерКриптографии()
	
	Контекст = Новый Структура;
	Контекст.Вставить("Операция");
	Контекст.Вставить("Оповещение");
	Контекст.Вставить("Программа");
	Контекст.Вставить("ПоказатьОшибку");
	Контекст.Вставить("АлгоритмПодписи");
	Контекст.Вставить("ИнтерактивныйРежим");
	Контекст.Вставить("Автоопределение");
	
	Возврат Контекст;
	
КонецФункции

// Продолжение процедуры СоздатьМенеджерКриптографии.
Асинх Процедура СоздатьМенеджерКриптографииПослеПодключенияРасширенияРаботыСКриптографией(Подключено, Контекст) Экспорт
	
	ЗаголовокФормы = НСтр("ru = 'Требуется программа электронной подписи и шифрования'");
	ЗаголовокОшибки = ЗаголовокОшибкиОперации(Контекст.Операция, Контекст.ПоказатьОшибку);
	ОписаниеОшибок = ЭлектроннаяПодписьСлужебныйКлиентСервер.НовоеОписаниеОшибок();
	ОписаниеОшибок.ЗаголовокОшибки = ЗаголовокОшибки;
	
	ТекстОбщейОшибки = "";
	
	Если Не ОбщегоНазначенияКлиент.ЭтоWindowsКлиент()
	   И Не ОбщегоНазначенияКлиент.ЭтоLinuxКлиент()
	   И Не ОбщегоНазначенияКлиент.ЭтоMacOSКлиент() Тогда
		
		ТекстОбщейОшибки = ТекстОшибкиУстройствоНеПоддерживается();
			
		СвойстваОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.НовыеСвойстваОшибки();
		СвойстваОшибки.НеПоддерживается = Истина;
	КонецЕсли;
	
	Если Не Подключено Тогда
		ТекстОбщейОшибки =
			НСтр("ru = 'В браузере установите расширение
			           |для работы с электронной подписью и шифрованием.'");
		СвойстваОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.НовыеСвойстваОшибки();
		СвойстваОшибки.НетРасширения = Истина;
	КонецЕсли;
	
	Если ТипЗнч(Контекст.Программа) = Тип("Строка") Или ТипЗнч(Контекст.Программа) = Тип("ДвоичныеДанные") Тогда
		
		ТребуетсяЗакрытыйКлюч = Контекст.Операция = "Подписание"
			Или Контекст.Операция = "Расшифровка";
		
		Результат = Ждать ЗаполнитьПараметрыДляСозданияМенеджераКриптографии(Контекст, ТребуетсяЗакрытыйКлюч);
		Контекст = Результат.Контекст;
		
		Если ЗначениеЗаполнено(Результат.Ошибка) Тогда
			
			Если ТребуетсяЗакрытыйКлюч И Контекст.Программа = Неопределено Тогда
				
				ТекстОбщейОшибки = Результат.Ошибка;
				СвойстваОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.НовыеСвойстваОшибки();
			
			Иначе
				
				СвойстваОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.НовыеСвойстваОшибки();
				СвойстваОшибки.Описание = Результат.Ошибка;
				ОписаниеОшибок.Ошибки.Добавить(СвойстваОшибки);
			
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ТекстОбщейОшибки) Тогда
		СвойстваОшибки.Описание = ТекстОбщейОшибки;
		
		ОписаниеОшибок.Общая = Истина;
		ОписаниеОшибок.Ошибки.Добавить(СвойстваОшибки);
		ОписаниеОшибок.ОписаниеОшибки = СокрЛП(ЗаголовокОшибки + Символы.ПС + ТекстОбщейОшибки);
		
		Если Контекст.ПоказатьОшибку = Неопределено Тогда
			ОписаниеОшибки = ОписаниеОшибок;
		Иначе
			ОписаниеОшибки = ОписаниеОшибок.ОписаниеОшибки;
		КонецЕсли;
		
		Если Контекст.ПоказатьОшибку = Истина Тогда
			ПоказатьОшибкуОбращенияКПрограмме(ЗаголовокФормы, "", ОписаниеОшибок, Новый Структура);
		КонецЕсли;
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, ОписаниеОшибки);
		Возврат;
	КонецЕсли;
	
	ПрограммыАвто = Неопределено;
	
	Если Контекст.Автоопределение И ТипЗнч(Контекст.Программа) <> Тип("Структура")
		И ТипЗнч(Контекст.Программа) <> Тип("ФиксированнаяСтруктура") Тогда
		
		КриптопровайдерыРезультат = Ждать УстановленныеКриптопровайдерыИзКэша();
		ПрограммыАвто = ЭлектроннаяПодписьСлужебныйКлиентСервер.РезультатПоискаКриптопровайдеров(КриптопровайдерыРезультат);
		
		Если ТипЗнч(ПрограммыАвто) = Тип("Строка") Тогда
			СвойстваОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.НовыеСвойстваОшибки();
			СвойстваОшибки.Описание = ПрограммыАвто;
			ОписаниеОшибок.Ошибки.Добавить(СвойстваОшибки);
			ПрограммыАвто = Неопределено;
		КонецЕсли;
		
	КонецЕсли;
	
	Контекст.Вставить("ЗаголовокФормы", ЗаголовокФормы);
	Контекст.Вставить("ОписаниеОшибок", ОписаниеОшибок);
	Контекст.Вставить("ЭтоLinux", ТребуетсяПутьКПрограмме());
		
	ОписанияПрограмм = ЭлектроннаяПодписьСлужебныйКлиентСервер.МенеджерКриптографииОписанияПрограмм(
		Контекст.Программа, ОписаниеОшибок.Ошибки, ЭлектроннаяПодписьКлиент.ОбщиеНастройки().ОписанияПрограмм, ПрограммыАвто);
	
	Контекст.Вставить("Менеджер", Неопределено);
	
	Если ОписанияПрограмм = Неопределено
		Или ОписанияПрограмм.Количество() = 0 Тогда
			СоздатьМенеджерКриптографииПослеЦикла(Контекст);
			Возврат;
	КонецЕсли;
	
	Контекст.Вставить("ОписанияПрограмм",  ОписанияПрограмм);
	Контекст.Вставить("Индекс", -1);
	
	СоздатьМенеджерКриптографииЦиклНачало(Контекст);
	
КонецПроцедуры

// Для процедуры СоздатьМенеджерКриптографии.
Функция ЗаголовокОшибкиОперации(Операция, ПоказатьОшибку)
	
	Если Операция = "Подписание" Тогда
		ЗаголовокОшибки = НСтр("ru = 'Не удалось подписать данные по причине:'");
		
	ИначеЕсли Операция = "ПроверкаПодписи" Тогда
		ЗаголовокОшибки = НСтр("ru = 'Не удалось проверить подпись по причине:'");
	
	ИначеЕсли Операция = "Шифрование" Тогда
		ЗаголовокОшибки = НСтр("ru = 'Не удалось зашифровать данные по причине:'");
		
	ИначеЕсли Операция = "Расшифровка" Тогда
		ЗаголовокОшибки = НСтр("ru = 'Не удалось расшифровать данные по причине:'");
		
	ИначеЕсли Операция = "ПроверкаСертификата" Тогда
		ЗаголовокОшибки = НСтр("ru = 'Не удалось проверить сертификат по причине:'");
		
	ИначеЕсли Операция = "ПолучениеСертификатов" Тогда
		ЗаголовокОшибки = НСтр("ru = 'Не удалось получить сертификаты по причине:'");
	
	ИначеЕсли Операция = "ЧтениеПодписи" Тогда
		ЗаголовокОшибки = НСтр("ru = 'Не удалось прочитать все свойства подписи по причине:'");
		
	ИначеЕсли Операция = "ПродлениеСрокаДействияПодписи" Тогда
		ЗаголовокОшибки = НСтр("ru = 'Не удалось продлить действие подписи по причине:'");
		
	ИначеЕсли Операция = Null И ПоказатьОшибку <> Истина Тогда
		ЗаголовокОшибки = "";
		
	ИначеЕсли Операция <> "" Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Ошибка в функции %1.
			           |Неверное значение параметра Операция ""%2"".'"), "МенеджерКриптографии", Операция);
	Иначе
		ЗаголовокОшибки = НСтр("ru = 'Не удалось выполнить операцию по причине:'");
	КонецЕсли;
	
	Возврат ЗаголовокОшибки;
	
КонецФункции

// Для процедуры СоздатьМенеджерКриптографии.
// 
// Возвращает уточненный контекст создания менеджера криптографии для указанных данных подписи или сертификата.
//  Контекст - см. КонтекстСоздатьМенеджерКриптографии
//
Асинх Функция ЗаполнитьПараметрыДляСозданияМенеджераКриптографии(Контекст, ТребуетсяЗакрытыйКлюч)
	
	Результат = Новый Структура("Контекст, Ошибка", Контекст, "");
	Данные = Контекст.Программа;
	
	Попытка
		
		ТипДанных = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОпределитьТипДанных(Данные);
		
	Исключение
		
		Результат.Контекст.Программа = Неопределено;
		Результат.Ошибка = СтроковыеФункцииКлиентСервер.ВставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось определить программу для переданных данных: %1'"),
			ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
		Возврат Результат;
		
	КонецПопытки;
	
	Если ТипДанных = "Сертификат" Тогда
		
		ПрограммаПоСертификатуРезультат = Ждать ПрограммаПоСертификату(Данные, ТребуетсяЗакрытыйКлюч,, Истина);
		Если ЗначениеЗаполнено(ПрограммаПоСертификатуРезультат.Ошибка) Тогда
			
			Результат.Ошибка = ЭлектроннаяПодписьСлужебныйКлиентСервер.ТекстОшибкиНеУдалосьОпределитьПрограмму(
				ПрограммаПоСертификатуРезультат.Ошибка);
			Результат.Контекст.АлгоритмПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.АлгоритмПодписиСертификата(Данные);
			Результат.Контекст.Программа = Неопределено;
			
		Иначе
			Результат.Контекст.Программа = ПрограммаПоСертификатуРезультат.Программа;
		КонецЕсли;
		
		Возврат Результат;
		
	ИначеЕсли ТипДанных = "Подпись" Тогда
		
		Результат.Контекст.Программа = Неопределено;
		Результат.Контекст.АлгоритмПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.АлгоритмСформированнойПодписи(Данные);
		Возврат Результат;
		
	ИначеЕсли ТипДанных = "ЗашифрованныеДанные" Тогда
		
		Результат.Контекст.Программа = Неопределено;
		Результат.Ошибка = НСтр("ru = 'Для определения программы для расшифровки в процедуру должны быть переданы данные сертификата.'");
		Возврат Результат;
		
	КонецЕсли;
	
	Результат.Контекст.Программа = Неопределено;
	Результат.Ошибка = НСтр("ru = 'Не удалось определить программу для переданных данных.'");
	
	Возврат Результат;
	
КонецФункции

// Продолжение процедуры СоздатьМенеджерКриптографии.
Процедура СоздатьМенеджерКриптографииЦиклНачало(Контекст) Экспорт
	
	Если Контекст.ОписанияПрограмм.Количество() <= Контекст.Индекс + 1 Тогда
		СоздатьМенеджерКриптографииПослеЦикла(Контекст);
		Возврат;
	КонецЕсли;
	
	Оповещение = Новый ОписаниеОповещения(
		"СоздатьМенеджерКриптографииЦиклНачалоПродолжение", ЭтотОбъект, Контекст);
	
	СтандартныеПодсистемыКлиент.НачатьВыполнениеОбработкиОповещения(Оповещение);
	
КонецПроцедуры

// Продолжение процедуры СоздатьМенеджерКриптографии.
Процедура СоздатьМенеджерКриптографииЦиклНачалоПродолжение(Результат, Контекст) Экспорт
	
	Контекст = Контекст; // см. КонтекстСоздатьМенеджерКриптографии
	Контекст.Индекс = Контекст.Индекс + 1;
	ОписаниеПрограммы = Контекст.ОписанияПрограмм[Контекст.Индекс]; // см. ЭлектроннаяПодписьСлужебныйПовтИсп.ОписаниеПрограммы
	Контекст.Вставить("ОписаниеПрограммы", ОписаниеПрограммы);
	
	Если ЗначениеЗаполнено(Контекст.АлгоритмПодписи) Тогда
		АлгоритмПодписиПоддерживается =
			ЭлектроннаяПодписьСлужебныйКлиентСервер.МенеджерКриптографииАлгоритмПодписиПоддерживается(
				ОписаниеПрограммы,
				?(Контекст.Свойство("Операция"), Контекст.Операция, ""),
				Контекст.АлгоритмПодписи,
				Контекст.ОписаниеОшибок.Ошибки,
				Ложь,
				Контекст.Программа <> Неопределено);
		
		Если Не АлгоритмПодписиПоддерживается Тогда
			Контекст.Менеджер = Неопределено;
			СоздатьМенеджерКриптографииЦиклНачало(Контекст);
			Возврат;
		КонецЕсли;
	КонецЕсли;
	
	Если ОписаниеПрограммы.Свойство("Автоопределение") Тогда
		ОписаниеПути = Новый Структура("ПутьКПрограмме, Существует", ОписаниеПрограммы.ПутьКПрограммеАвто, Истина);
		СоздатьМенеджерКриптографииЦиклПослеПолученияПутиКПрограмме(ОписаниеПути, Контекст);
		Возврат;
	КонецЕсли;
	
	ИдентификаторПутиКПрограмме = ?(ЗначениеЗаполнено(ОписаниеПрограммы.Ссылка),
		ОписаниеПрограммы.Ссылка, ОписаниеПрограммы.Идентификатор);
	
	ПолучитьПутьКПрограмме(Новый ОписаниеОповещения("СоздатьМенеджерКриптографииЦиклПослеПолученияПутиКПрограмме",
		ЭтотОбъект, Контекст), ИдентификаторПутиКПрограмме);
	
КонецПроцедуры

Процедура СоздатьМенеджерКриптографииЦиклПослеПолученияПутиКПрограмме(ОписаниеПути, Контекст) Экспорт
	
	СвойстваПрограммы = ЭлектроннаяПодписьСлужебныйКлиентСервер.МенеджерКриптографииСвойстваПрограммы(
		Контекст.ОписаниеПрограммы,
		Контекст.ЭтоLinux,
		Контекст.ОписаниеОшибок.Ошибки,
		Ложь,
		ОписаниеПути);
	
	Если СвойстваПрограммы = Неопределено Тогда
		СоздатьМенеджерКриптографииЦиклНачало(Контекст);
		Возврат;
	КонецЕсли;
	
	Контекст.Вставить("СвойстваПрограммы", СвойстваПрограммы);
	
	СредстваКриптографии.НачатьПолучениеИнформацииМодуляКриптографии(Новый ОписаниеОповещения(
			"СоздатьМенеджерКриптографииЦиклПослеПолученияИнформации", ЭтотОбъект, Контекст,
			"СоздатьМенеджерКриптографииЦиклПослеОшибкиПолученияИнформации", ЭтотОбъект),
		Контекст.СвойстваПрограммы.ИмяПрограммы,
		Контекст.СвойстваПрограммы.ПутьКПрограмме,
		Контекст.СвойстваПрограммы.ТипПрограммы);
	
КонецПроцедуры

// Продолжение процедуры СоздатьМенеджерКриптографии.
Процедура СоздатьМенеджерКриптографииЦиклПослеОшибкиПолученияИнформации(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
	
	СоздатьМенеджерКриптографииЦиклПриОшибкеИнициализации(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст);
	
КонецПроцедуры

// Продолжение процедуры СоздатьМенеджерКриптографии.
// 
// Параметры:
//   ИнформацияМодуля - ИнформацияМодуляКриптографии
//   Контекст - Структура
//
Процедура СоздатьМенеджерКриптографииЦиклПослеПолученияИнформации(ИнформацияМодуля, Контекст) Экспорт
	
	Если ИнформацияМодуля = Неопределено Тогда
		ЭлектроннаяПодписьСлужебныйКлиентСервер.МенеджерКриптографииПрограммаНеНайдена(
			Контекст.ОписаниеПрограммы, Контекст.ОписаниеОшибок.Ошибки, Ложь);
		
		Контекст.Менеджер = Неопределено;
		СоздатьМенеджерКриптографииЦиклНачало(Контекст);
		Возврат;
	КонецЕсли;
	
	Если Не Контекст.ЭтоLinux Тогда
		ИмяПрограммыПолученное = ИнформацияМодуля.Имя;
		
		ИмяПрограммыСовпадает = ЭлектроннаяПодписьСлужебныйКлиентСервер.МенеджерКриптографииИмяПрограммыСовпадает(
			Контекст.ОписаниеПрограммы, ИмяПрограммыПолученное, Контекст.ОписаниеОшибок.Ошибки, Ложь);
		
		Если Не ИмяПрограммыСовпадает Тогда
			Контекст.Менеджер = Неопределено;
			СоздатьМенеджерКриптографииЦиклНачало(Контекст);
			Возврат;
		КонецЕсли;
	КонецЕсли;
	
	Контекст.Менеджер = Новый МенеджерКриптографии;
	
	Если Не Контекст.ИнтерактивныйРежим Тогда
		Контекст.Менеджер.НачатьИнициализацию(Новый ОписаниеОповещения(
				"СоздатьМенеджерКриптографииЦиклПослеИнициализации", ЭтотОбъект, Контекст,
				"СоздатьМенеджерКриптографииЦиклПриОшибкеИнициализации", ЭтотОбъект),
			Контекст.СвойстваПрограммы.ИмяПрограммы,
			Контекст.СвойстваПрограммы.ПутьКПрограмме,
			Контекст.СвойстваПрограммы.ТипПрограммы);
	Иначе
		Контекст.Менеджер.НачатьИнициализацию(Новый ОписаниеОповещения(
				"СоздатьМенеджерКриптографииЦиклПослеИнициализации", ЭтотОбъект, Контекст,
				"СоздатьМенеджерКриптографииЦиклПриОшибкеИнициализации", ЭтотОбъект),
			Контекст.СвойстваПрограммы.ИмяПрограммы,
			Контекст.СвойстваПрограммы.ПутьКПрограмме,
			Контекст.СвойстваПрограммы.ТипПрограммы,
			ИспользованиеИнтерактивногоРежимаКриптографииИспользовать());
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры СоздатьМенеджерКриптографии.
Процедура СоздатьМенеджерКриптографииЦиклПриОшибкеИнициализации(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
	
	СтандартнаяОбработка = Ложь;
	Контекст.Менеджер = Неопределено;
	
	ОписаниеПрограммы = Контекст.ОписаниеПрограммы; // см. ЭлектроннаяПодписьСлужебныйПовтИсп.ОписаниеПрограммы
	ЭлектроннаяПодписьСлужебныйКлиентСервер.МенеджерКриптографииДобавитьОшибку(
		Контекст.ОписаниеОшибок.Ошибки,
		ОписаниеПрограммы.Ссылка,
		ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке),
		Ложь, Истина, Истина);
	
	СоздатьМенеджерКриптографииЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры СоздатьМенеджерКриптографии.
Процедура СоздатьМенеджерКриптографииЦиклПослеИнициализации(Неопределен, Контекст) Экспорт
	
	АлгоритмыУстановлены = ЭлектроннаяПодписьСлужебныйКлиентСервер.МенеджерКриптографииАлгоритмыУстановлены(
		Контекст.ОписаниеПрограммы,
		Контекст.Менеджер,
		Контекст.ОписаниеОшибок.Ошибки);
	
	Если Не АлгоритмыУстановлены Тогда
		СоздатьМенеджерКриптографииЦиклНачало(Контекст);
		Возврат;
	КонецЕсли;
	
	// Требуемый менеджер криптографии получен.
	СоздатьМенеджерКриптографииПослеЦикла(Контекст);
	
КонецПроцедуры

// Продолжение процедуры СоздатьМенеджерКриптографии.
Процедура СоздатьМенеджерКриптографииПослеЦикла(Контекст)
	
	Если Контекст.Менеджер <> Неопределено Или Не Контекст.Свойство("ЗаголовокФормы") Тогда
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Контекст.Менеджер);
		Возврат;
	КонецЕсли;
	
	ОписаниеОшибок = Контекст.ОписаниеОшибок;
	ЭлектроннаяПодписьСлужебныйКлиентСервер.МенеджерКриптографииЗаполнитьПредставлениеОшибок(
		ОписаниеОшибок,
		Контекст.Программа,
		Контекст.АлгоритмПодписи,
		ПользователиКлиент.ЭтоПолноправныйПользователь(),
		Ложь);
	
	Если Контекст.ПоказатьОшибку = Неопределено Тогда
		ОписаниеОшибки = ОписаниеОшибок;
	Иначе
		ОписаниеОшибки = ОписаниеОшибок.ОписаниеОшибки;
	КонецЕсли;
	
	Если Контекст.ПоказатьОшибку = Истина Тогда
		ПоказатьОшибкуОбращенияКПрограмме(Контекст.ЗаголовокФормы, "", ОписаниеОшибок, Новый Структура);
	КонецЕсли;
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, ОписаниеОшибки);
	
КонецПроцедуры

Асинх Функция ОбъектВнешнейКомпонентыExtraCryptoAPI(ПредложитьУстановить = Истина, ТекстПояснения = Неопределено)
	
	Если Не ОбщегоНазначенияКлиент.ЭтоWindowsКлиент()
	   И Не ОбщегоНазначенияКлиент.ЭтоLinuxКлиент()
	   И Не ОбщегоНазначенияКлиент.ЭтоMacOSКлиент() Тогда
		
		ВызватьИсключение ТекстОшибкиУстройствоНеПоддерживается();
		
	КонецЕсли;
	
	ОписаниеКомпоненты = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОписаниеКомпоненты();
	ПараметрыПодключения = ОбщегоНазначенияКлиент.ПараметрыПодключенияКомпоненты();
	Если ТекстПояснения = Неопределено Тогда
		ПараметрыПодключения.ТекстПояснения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Для упрощения работы с криптографией требуется установка внешней компоненты %1.'"),
			ОписаниеКомпоненты.ИмяОбъекта);
	Иначе
		ПараметрыПодключения.ТекстПояснения = ТекстПояснения;
	КонецЕсли;
	ПараметрыПодключения.ПредложитьУстановить = ПредложитьУстановить;
	ПараметрыПодключения.ПредложитьЗагрузить = Ложь;
	
	Результат = Ждать ОбщегоНазначенияКлиент.ПодключитьКомпонентуИзМакетаАсинх(
		ОписаниеКомпоненты.ИмяОбъекта,
		ОписаниеКомпоненты.ПолноеИмяМакета,
		ПараметрыПодключения);
	
	Если Результат.Подключено Тогда
		ОбъектКомпоненты = Результат.ПодключаемыйМодуль;
		ОбъектКомпоненты = Ждать НастроитьКомпоненту(ОбъектКомпоненты);
	ИначеЕсли ЗначениеЗаполнено(Результат.ОписаниеОшибки) Тогда
		ВызватьИсключение Результат.ОписаниеОшибки;
	Иначе
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось подключить внешнюю компоненту %1.'"), ОписаниеКомпоненты.ИмяОбъекта);
			ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	Возврат ОбъектКомпоненты;
	
КонецФункции

Асинх Функция НастроитьКомпоненту(ОбъектКомпоненты)
	
	Попытка
		Ждать ОбъектКомпоненты.УстановитьСоответствиеOIDАсинх(
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ИдентификаторыАлгоритмовХешированияИОткрытогоКлюча());
	Исключение
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось установить свойство %1 компоненты %2 по причине:
				|%3'"), "СоответствиеOID", "ExtraCryptoAPI", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;
	
	Возврат ОбъектКомпоненты;
	
КонецФункции

Асинх Функция ПрограммаПоСертификату(Сертификат,
	ТребуетсяЗакрытыйКлюч = Неопределено, ОбъектКомпоненты = Неопределено, ПредложитьУстановить = Ложь) Экспорт
	
	Результат = Новый Структура("Программа, Ошибка");
	
	Если ОбъектКомпоненты = Неопределено Тогда
		
		ТекстПояснения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Для получения данных о программе для работы с сертификатом электронной подписи требуется установка внешней компоненты %1.'"),
			"ExtraCryptoAPI");
		
		Попытка
			ОбъектКомпоненты = Ждать ОбъектВнешнейКомпонентыExtraCryptoAPI(ПредложитьУстановить, ТекстПояснения);
		Исключение
			Результат.Ошибка = ТекстОшибкиНеУстановленаКомпонента();
			Возврат Результат;
		КонецПопытки;
	КонецЕсли;

	Сертификат = Ждать СертификатBase64Строка(Сертификат);
	
	Если ТребуетсяЗакрытыйКлюч <> Ложь Тогда
		
		Попытка
			РезультатСвойстваКриптопровайдера = Ждать ОбъектКомпоненты.ПолучитьСвойстваКриптопровайдераАсинх(Сертификат);
			ТекущийКриптопровайдер = КриптопровайдерИзОтветаКомпоненты(РезультатСвойстваКриптопровайдера.Значение);
		Исключение
			Результат.Ошибка = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
			Возврат Результат;
		КонецПопытки;
		
		ПрограммыПоИменамСТипом = ЭлектроннаяПодписьКлиент.ОбщиеНастройки().ПрограммыПоИменамСТипом;
		РасширенноеОписаниеПрограммы = ЭлектроннаяПодписьСлужебныйКлиентСервер.РасширенноеОписаниеПрограммы(
			ТекущийКриптопровайдер, ПрограммыПоИменамСТипом);
			
		Если РасширенноеОписаниеПрограммы <> Неопределено Тогда
			Результат.Программа = РасширенноеОписаниеПрограммы;
			Возврат Результат;
		ИначеЕсли ТребуетсяЗакрытыйКлюч = Истина И ТекущийКриптопровайдер.Получить("type") <> 0 Тогда
			Результат.Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Сертификат связан с программой %1 с типом %2, настройте ее в справочнике для использования.'"),
				ТекущийКриптопровайдер.Получить("name"),
				ТекущийКриптопровайдер.Получить("type"));
			Возврат Результат;
		КонецЕсли;
		
	КонецЕсли;
	
	Если ТребуетсяЗакрытыйКлюч = Истина Тогда
		Результат.Ошибка = ТекстОшибкиНеУдалосьОпределитьПрограммуПоЗакрытомуКлючуСертификата();
		Возврат Результат;
	КонецЕсли; 
	
	СвойстваСертификата = Ждать ПолучитьСвойстваСертификатаАсинх(Сертификат, ОбъектКомпоненты);
	Если ЗначениеЗаполнено(СвойстваСертификата.Ошибка) Тогда
		Результат.Ошибка = СвойстваСертификата.Ошибка;
		Возврат Результат;
	КонецЕсли;
	
	СвойстваСертификата = СвойстваСертификата.СвойстваСертификата;
	
	УстановленныеКриптопровайдеры = Ждать УстановленныеКриптопровайдерыИзКэша(
		ПредложитьУстановить);
		
	Если УстановленныеКриптопровайдеры.ПроверкаВыполнена Тогда
		
		ПрограммыПоИдентификаторамАлгоритмовОткрытогоКлюча = ЭлектроннаяПодписьКлиент.ОбщиеНастройки().ПрограммыПоИдентификаторамАлгоритмовОткрытогоКлюча;
		Ошибка = "";
		РасширенноеОписаниеПрограммы = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОпределитьПрограмму(СвойстваСертификата,
			УстановленныеКриптопровайдеры.Криптопровайдеры, ПрограммыПоИдентификаторамАлгоритмовОткрытогоКлюча, Ошибка);
		Результат.Программа = РасширенноеОписаниеПрограммы;
		
		Если Результат.Программа = Неопределено Тогда
			Результат.Ошибка = Ошибка;
		КонецЕсли;
		
		Возврат Результат;
		
	Иначе
		Результат.Ошибка = УстановленныеКриптопровайдеры.Ошибка;
		Возврат Результат;
	КонецЕсли;

КонецФункции

Функция ТекстОшибкиНеУдалосьОпределитьПрограммуПоЗакрытомуКлючуСертификата()
	
	Возврат НСтр("ru = 'Не удалось определить программу по закрытому ключу сертификата.'");
	
КонецФункции

Функция КриптопровайдерИзОтветаКомпоненты(Знач Текст)

	Результат = Новый Соответствие;

	Попытка
		
		ЗаполнитьСоответствиеИзОтветаJSON(Результат, Текст);
		Возврат Результат;

	Исключение

		ИнформацияОбОшибке = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());

		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Не удалось прочитать ответ компоненты: %1
						 |%2'"), Текст, ИнформацияОбОшибке);

	КонецПопытки;
	
	Возврат Результат;
	
КонецФункции

// Для функции КриптопровайдерИзОтветаКомпоненты
Процедура ЗаполнитьСоответствиеИзОтветаJSON(Результат, Знач ТекстJSON)
	
	ТекстJSON = СтрЗаменить(СокрЛП(ТекстJSON), Символы.ПС, "");
	ТекстJSON = СокрЛП(Сред(ТекстJSON, 2, СтрДлина(ТекстJSON)-2));
	
	Пока ТекстJSON <> "" Цикл
		
		Позиция = СтрНайти(ТекстJSON, ":");
		Если Позиция = 0 Тогда
			Прервать;
		КонецЕсли;
		
		ИмяЗначения = СокрЛП(Лев(ТекстJSON, Позиция-1));
		ИмяЗначения = СтрЗаменить(ИмяЗначения, """","");
		
		ЭтоЧисло = Ложь;
		ТекстJSON = СокрЛП(Сред(ТекстJSON, Позиция+1));
		Если Лев(ТекстJSON, 1) = """" Тогда
			ТекстJSON = СокрЛП(Сред(ТекстJSON, 2));
		Иначе
			ЭтоЧисло = Истина;
		КонецЕсли; 
		
		Позиция = 0;
		Для НоваяПозиция = 1 По СтрДлина(ТекстJSON) Цикл
			Символ = Сред(ТекстJSON, НоваяПозиция, 1);
			
			СледующийСимвол = Неопределено;
			Если Символ = "," Тогда
				Для СледующаяПозиция = НоваяПозиция + 1 По СтрДлина(ТекстJSON) Цикл
					СледующийСимвол = Сред(ТекстJSON, СледующаяПозиция, 1);
					Если СледующийСимвол <> " " Тогда
						Прервать;
					КонецЕсли; 
				КонецЦикла; 
			КонецЕсли; 
			Если Символ = "," И (СледующийСимвол = Неопределено ИЛИ СледующийСимвол = """") Тогда
				Позиция = НоваяПозиция;
				Прервать;
			КонецЕсли;
		КонецЦикла;
		
		Если Позиция = 0 Тогда
			Значение = ТекстJSON;
			ТекстJSON = "";
		Иначе
			Значение = Лев(ТекстJSON, Позиция-1);
			ТекстJSON = СокрЛП(Сред(ТекстJSON, Позиция + ?(Сред(ТекстJSON, Позиция, 1) = ",", 1, 0)));
		КонецЕсли;
		
		Значение = СокрЛП(Значение);
		Если Значение = "true" Тогда
			Значение = Истина;
		ИначеЕсли Значение = "false" Тогда
			Значение = Ложь;
		ИначеЕсли Значение = "null" Тогда
			Значение = Неопределено;
		Иначе
			Если ЭтоЧисло Тогда
				Значение = СтроковыеФункцииКлиентСервер.СтрокаВЧисло(Значение);
			Иначе
				Значение = Лев(Значение, СтрДлина(Значение)-1);
			КонецЕсли;
		КонецЕсли;
		
		Результат.Вставить(ИмяЗначения, Значение);
		
	КонецЦикла;
	
КонецПроцедуры

// Контейнеры по сертификату.
// 
// Параметры:
//  Сертификат - ДвоичныеДанные
//             - Строка - адрес во временном хранилище
//             - Строка - строковое представление сертификата в формате Base64
//             - СертификатКриптографии
//  ОбъектКомпоненты - ОбъектВнешнейКомпоненты  - экземпляр объекта внешней компоненты
// 
// Возвращаемое значение:
//  Обещание - Массив из см. НовыеСвойстваКонтейнера
//
Асинх Функция КонтейнерыПоСертификату(Сертификат, ОбъектКомпоненты = Неопределено) Экспорт
	
	Если ОбъектКомпоненты = Неопределено Тогда
		ОбъектКомпоненты = Ждать ОбъектВнешнейКомпонентыExtraCryptoAPI(Истина);
	КонецЕсли;
	
	Сертификат = Ждать СертификатBase64Строка(Сертификат);
	
	Контейнеры = Новый Массив;
	СвойстваСертификатаРезультат = Ждать ПолучитьСвойстваСертификатаАсинх(Сертификат, ОбъектКомпоненты);
	
	Если Не ПустаяСтрока(СвойстваСертификатаРезультат.Ошибка) Тогда
		ВызватьИсключение СвойстваСертификатаРезультат.Ошибка;
	КонецЕсли;
	
	СвойстваСертификата = СвойстваСертификатаРезультат.СвойстваСертификата;
	
	ИменаКонтейнеров = Новый Соответствие;
	ПрограммаПоСертификатуРезультат = Ждать ПрограммаПоСертификату(Сертификат, Неопределено, ОбъектКомпоненты, Истина);
	
	Если ПрограммаПоСертификатуРезультат.Программа <> Неопределено Тогда
		Контейнеры = Ждать ДобавитьКонтейнерыПоСертификатуПоКриптопровайдеру(
			СвойстваСертификата, ПрограммаПоСертификатуРезультат.Программа,
			ОбъектКомпоненты, Контейнеры, ИменаКонтейнеров);
			
		Для Каждого ТекущийКонтейнер Из Контейнеры Цикл
			ИменаКонтейнеров.Вставить(ТекущийКонтейнер.Имя, Истина);
		КонецЦикла;
	КонецЕсли;
	
	КриптопровайдерыРезультат = Ждать УстановленныеКриптопровайдеры(ОбъектКомпоненты);
	
	Если Не КриптопровайдерыРезультат.ПроверкаВыполнена Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось получить список установленных криптопровайдеров:
				|%1'"), КриптопровайдерыРезультат.Ошибка);
	КонецЕсли;
	
	Для Каждого ТекущийКриптопровайдер Из КриптопровайдерыРезультат.Криптопровайдеры Цикл
		Контейнеры = Ждать ДобавитьКонтейнерыПоСертификатуПоКриптопровайдеру(
			СвойстваСертификата, ТекущийКриптопровайдер,
			ОбъектКомпоненты, Контейнеры, ИменаКонтейнеров);
		Для Каждого ТекущийКонтейнер Из Контейнеры Цикл
			ИменаКонтейнеров.Вставить(ТекущийКонтейнер.Имя, Истина);
		КонецЦикла;
	КонецЦикла;
	
	Возврат Контейнеры;
	
КонецФункции

// Для КонтейнерыПоСертификату
Асинх Функция ДобавитьКонтейнерыПоСертификатуПоКриптопровайдеру(СвойстваСертификата, Криптопровайдер, ОбъектКомпоненты, Контейнеры, ИменаКонтейнеров)
	
	Результат = Ждать ОбъектКомпоненты.НайтиКонтейнерыАсинх(
			Криптопровайдер.ТипПрограммы,
			Криптопровайдер.ИмяПрограммы,
			СвойстваСертификата.Сертификат);

	Если ЗначениеЗаполнено(Результат.Значение) И Результат.Значение <> "null" Тогда
		Прочитано = ЭлектроннаяПодписьСлужебныйКлиентСервер.ПрочитатьОтветКомпоненты(Результат.Значение);
	Иначе
		Возврат Контейнеры;
	КонецЕсли;

	КонтейнерыКриптопровайдера = Прочитано.Получить(Криптопровайдер.ИмяПрограммы);
	СвойстваКонтейнеров = КонтейнерыКриптопровайдера.Получить("containers");

	Если СвойстваКонтейнеров = Неопределено Тогда
		Возврат Контейнеры;
	КонецЕсли;

	Для Каждого ТекущийКонтейнер Из СвойстваКонтейнеров Цикл

		ИмяКонтейнера = ТекущийКонтейнер.Получить("FQCN");

		Если ИменаКонтейнеров.Получить(ИмяКонтейнера) = Истина Тогда
			Продолжить;
		КонецЕсли;

		ЭтоТекущийКонтейнер = ИмяКонтейнера = СвойстваСертификата.ИмяКонтейнера;

		Контейнер = НовыеСвойстваКонтейнера();
		Контейнер.Имя = ИмяКонтейнера;
		Контейнер.ДружественноеИмя = ТекущийКонтейнер.Получить("Friendly name");
		Если Не ЗначениеЗаполнено(Контейнер.ДружественноеИмя) Тогда
			Контейнер.ДружественноеИмя = Контейнер.Имя;
		КонецЕсли;
		Контейнер.ТипПрограммы = Криптопровайдер.ТипПрограммы;
		Контейнер.ИмяПрограммы = Криптопровайдер.ИмяПрограммы;
		Контейнер.ПутьКПрограмме = Криптопровайдер.ПутьКПрограммеАвто;

		Контейнер.Вставить("ЭтоТекущийКонтейнер", ЭтоТекущийКонтейнер);

		Контейнеры.Добавить(Контейнер);

	КонецЦикла;
	
	Возврат Контейнеры;
	
КонецФункции

// Свойства контейнера закрытого ключа.
// 
// Возвращаемое значение:
//  Структура:
//   * Имя - Строка 
//   * ДружественноеИмя - Строка
//   * ТипПрограммы - Число
//   * ИмяПрограммы - Строка
//   * ПутьКПрограмме - Строка
//
Функция НовыеСвойстваКонтейнера() Экспорт
	
	Контейнер = Новый Структура;
	Контейнер.Вставить("Имя", "");
	Контейнер.Вставить("ДружественноеИмя", "");
	Контейнер.Вставить("ТипПрограммы", 0);
	Контейнер.Вставить("ИмяПрограммы", "");
	Контейнер.Вставить("ПутьКПрограмме", "");
	
	Возврат Контейнер;
	
КонецФункции


// Только для внутреннего назначения.
// 
// Параметры:
//  ПараметрыСоздания - см. ПараметрыДобавленияСертификата
//  ОбработчикЗавершения - Неопределено - обработчик завершения
//
Процедура ДобавитьСертификат(ПараметрыСоздания = Неопределено, ОбработчикЗавершения = Неопределено) Экспорт
	
	ПараметрыДобавленияСертификата = ПараметрыДобавленияСертификата();
	ЗаполнитьЗначенияСвойств(ПараметрыДобавленияСертификата, ПараметрыСоздания);
	ПараметрыДобавленияСертификата.ОбработчикЗавершения = ОбработчикЗавершения;
	
	Если ПараметрыДобавленияСертификата.СоздатьЗаявление = Истина Тогда
		ДобавитьСертификатПослеВыбораНазначения("ЗаявлениеНаВыпускСертификата", ПараметрыДобавленияСертификата);
		Возврат;
	КонецЕсли;
	
	Если ПараметрыДобавленияСертификата.СкрытьЗаявление = Неопределено Тогда
		ПараметрыДобавленияСертификата.СкрытьЗаявление = Истина;
	КонецЕсли;
	
	Форма = ОткрытьФорму("Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования.Форма.ДобавлениеСертификата",
		Новый Структура("СкрытьЗаявление", ПараметрыДобавленияСертификата.СкрытьЗаявление),,,,,
		Новый ОписаниеОповещения("ДобавитьСертификатПослеВыбораНазначения", ЭтотОбъект, ПараметрыДобавленияСертификата));
	
	Если Форма = Неопределено Тогда
		ДобавитьСертификатПослеВыбораНазначения("ДляПодписанияШифрованияИРасшифровки", ПараметрыДобавленияСертификата);
	КонецЕсли;
	
КонецПроцедуры

// Только для внутреннего назначения.
// 
// Возвращаемое значение:
//  Структура - параметры добавления сертификата:
//   * ВЛичныйСписок - Булево - если не указано, значит Ложь.
//   * Организация - ОпределяемыйТип.Организация - значение по умолчанию.
//   * ФизическоеЛицо - СправочникСсылка - физическое лицо, для которого нужно создать заявление
//                       на выпуск сертификата (когда заполнено, имеет приоритет над организацией).
//                       Значение по умолчанию - Неопределено.
//   * СертификатОснование - СправочникСсылка.СертификатыКлючейЭлектроннойПодписиИШифрования - сертификат, который надо перевыпустить.
//   * ОбработчикЗавершения - ОписаниеОповещения
//   * СоздатьЗаявление - Булево - сразу открыть форму создания заявления на выпуск сертификата.
//   * СкрытьЗаявление - Булево - не предлагать создать заявление на выпуск сертификата.
//
Функция ПараметрыДобавленияСертификата() Экспорт
	
	Структура = Новый Структура;
	Структура.Вставить("ВЛичныйСписок", Ложь);
	Структура.Вставить("Организация", Неопределено);
	Структура.Вставить("ФизическоеЛицо", Неопределено);
	Структура.Вставить("СертификатОснование", Неопределено);
	Структура.Вставить("ОбработчикЗавершения", Неопределено);
	Структура.Вставить("СоздатьЗаявление", Неопределено);
	Структура.Вставить("СкрытьЗаявление", Неопределено);
	
	Возврат Структура;
	
КонецФункции

// Только для внутреннего назначения.
Процедура ДобавитьСертификатПослеВыбораНазначения(Назначение, ПараметрыСоздания) Экспорт
	
	ПараметрыФормы = Новый Структура;
	
	Если Назначение = "ЗаявлениеНаВыпускСертификата" Тогда
		ПараметрыФормы.Вставить("Организация", ПараметрыСоздания.Организация);
		ПараметрыФормы.Вставить("ФизическоеЛицо", ПараметрыСоздания.ФизическоеЛицо);
		ПараметрыФормы.Вставить("СертификатОснование", ПараметрыСоздания.СертификатОснование);
		ИмяФормы = "Обработка.ЗаявлениеНаВыпускНовогоКвалифицированногоСертификата.Форма.Форма";
		ОткрытьФорму(ИмяФормы, ПараметрыФормы, , , , , ПараметрыСоздания.ОбработчикЗавершения);
		Возврат;
	КонецЕсли;
	
	Если Назначение = "ТолькоДляШифрованияИзФайла" Тогда
		ДобавитьСертификатТолькоДляШифрованияИзФайла(ПараметрыСоздания);
		Возврат;
	КонецЕсли;
	
	Если Назначение = "ТолькоДляШифрованияИзФайлов" Тогда
		ДобавитьСертификатТолькоДляШифрованияИзФайла(ПараметрыСоздания, Истина);
		Возврат;
	КонецЕсли;
	
	Если Назначение = "ТолькоДляШифрованияИзКаталога" Тогда
		ДобавитьСертификатТолькоДляШифрованияИзКаталога(ПараметрыСоздания);
		Возврат;
	КонецЕсли;
	
	Если Назначение <> "ТолькоДляШифрования" Тогда
		ПараметрыФормы.Вставить("ДляШифрованияИРасшифровки", Неопределено);
		
		Если Назначение = "ДляШифрованияИРасшифровки" Тогда
			ПараметрыФормы.Вставить("ДляШифрованияИРасшифровки", Истина);
		
		ИначеЕсли Назначение <> "ДляПодписанияШифрованияИРасшифровки" Тогда
			Возврат;
		КонецЕсли;
		
		ПараметрыФормы.Вставить("ДобавлениеВСписок", Истина);
		ПараметрыФормы.Вставить("ЛичныйСписокПриДобавлении", ПараметрыСоздания.ВЛичныйСписок);
		ПараметрыФормы.Вставить("Организация", ПараметрыСоздания.Организация);
		ВыборСертификатаДляПодписанияИлиРасшифровки(ПараметрыФормы, , ПараметрыСоздания.ОбработчикЗавершения);
		Возврат;
	КонецЕсли;
	
	Контекст = Новый Структура;
	Контекст.Вставить("ПараметрыСоздания", ПараметрыСоздания);
	
	ПолучитьСвойстваСертификатовНаКлиенте(Новый ОписаниеОповещения(
			"ДобавитьСертификатПослеПолученияСвойствСертификатовНаКлиенте", ЭтотОбъект, Контекст),
		Ложь, Ложь);
	
КонецПроцедуры

// Продолжение процедуры ДобавитьСертификатПослеВыбораНазначения.
Процедура ДобавитьСертификатПослеПолученияСвойствСертификатовНаКлиенте(Результат, Контекст) Экспорт
	
	ПараметрыФормы = Новый Структура;
	ПараметрыФормы.Вставить("СвойстваСертификатовНаКлиенте",        Результат.СвойстваСертификатовНаКлиенте);
	ПараметрыФормы.Вставить("ОшибкаПолученияСертификатовНаКлиенте", Результат.ОшибкаПолученияСертификатовНаКлиенте);
	
	Если Контекст.ПараметрыСоздания.Свойство("ВЛичныйСписок") Тогда
		ПараметрыФормы.Вставить("ЛичныйСписокПриДобавлении", Контекст.ПараметрыСоздания.ВЛичныйСписок);
	КонецЕсли;
	Если Контекст.ПараметрыСоздания.Свойство("Организация") Тогда
		ПараметрыФормы.Вставить("Организация", Контекст.ПараметрыСоздания.Организация);
	КонецЕсли;
	
	ОбработчикЗавершения = Неопределено;
	Контекст.ПараметрыСоздания.Свойство("ОбработчикЗавершения", ОбработчикЗавершения);
	
	ОткрытьФорму("Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования.Форма.ДобавлениеСертификатаДляШифрования",
		ПараметрыФормы, , , , , ОбработчикЗавершения);
	
КонецПроцедуры

// Только для внутреннего назначения.
Процедура ПолучитьСвойстваСертификатовНаКлиенте(Оповещение, Личные, БезОтбора, ТолькоОтпечатки = Ложь, ПоказатьОшибку = Неопределено) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("ОшибкаПолученияСертификатовНаКлиенте", Новый Структура);
	Результат.Вставить("СвойстваСертификатовНаКлиенте", ?(ТолькоОтпечатки, Новый Соответствие, Новый Массив));
	
	Контекст = Новый Структура;
	Контекст.Вставить("Оповещение",      Оповещение);
	Контекст.Вставить("Личные",          Личные);
	Контекст.Вставить("БезОтбора",       БезОтбора);
	Контекст.Вставить("ТолькоОтпечатки", ТолькоОтпечатки);
	Контекст.Вставить("Результат",       Результат);
	
	ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
	ПараметрыСоздания.ПоказатьОшибку = ПоказатьОшибку;
	
	СоздатьМенеджерКриптографии(Новый ОписаниеОповещения(
			"ПолучитьСвойстваСертификатовНаКлиентеПослеСозданияМенеджераКриптографии", ЭтотОбъект, Контекст),
		"ПолучениеСертификатов", ПараметрыСоздания);
	
КонецПроцедуры

// Продолжение процедуры ПолучитьСвойстваСертификатовНаКлиенте.
Процедура ПолучитьСвойстваСертификатовНаКлиентеПослеСозданияМенеджераКриптографии(МенеджерКриптографии, Контекст) Экспорт
	
	Если ТипЗнч(МенеджерКриптографии) <> Тип("МенеджерКриптографии") Тогда
		Контекст.Результат.ОшибкаПолученияСертификатовНаКлиенте = МенеджерКриптографии;
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Контекст.Результат);
		Возврат;
	КонецЕсли;
	
	Контекст.Вставить("МенеджерКриптографии", МенеджерКриптографии);
	
	Контекст.МенеджерКриптографии.НачатьПолучениеХранилищаСертификатов(
		Новый ОписаниеОповещения(
			"ПолучитьСвойстваСертификатовНаКлиентеПослеПолученияПерсональногоХранилища", ЭтотОбъект, Контекст),
		ТипХранилищаСертификатовКриптографии.ПерсональныеСертификаты);
	
КонецПроцедуры

// Продолжение процедуры ПолучитьСвойстваСертификатовНаКлиенте.
Процедура ПолучитьСвойстваСертификатовНаКлиентеПослеПолученияПерсональногоХранилища(Хранилище, Контекст) Экспорт
	
	Хранилище.НачатьПолучениеВсех(Новый ОписаниеОповещения(
		"ПолучитьСвойстваСертификатовНаКлиентеПослеПолученияВсехПерсональныхСертификатов", ЭтотОбъект, Контекст));
	
КонецПроцедуры

// Продолжение процедуры ПолучитьСвойстваСертификатовНаКлиенте.
Процедура ПолучитьСвойстваСертификатовНаКлиентеПослеПолученияВсехПерсональныхСертификатов(Массив, Контекст) Экспорт
	
	Контекст.Вставить("МассивСертификатов", Массив);
	
	Если Контекст.Личные Тогда
		ПолучитьСвойстваСертификатовНаКлиентеПослеПолученияВсех(Контекст);
		Возврат;
	КонецЕсли;
	
	Контекст.МенеджерКриптографии.НачатьПолучениеХранилищаСертификатов(
		Новый ОписаниеОповещения(
			"ПолучитьСвойстваСертификатовНаКлиентеПослеПолученияХранилищаПолучателей", ЭтотОбъект, Контекст),
		ТипХранилищаСертификатовКриптографии.СертификатыПолучателей);
	
КонецПроцедуры

// Продолжение процедуры ПолучитьСвойстваСертификатовНаКлиенте.
Процедура ПолучитьСвойстваСертификатовНаКлиентеПослеПолученияХранилищаПолучателей(Хранилище, Контекст) Экспорт
	
	Хранилище.НачатьПолучениеВсех(Новый ОписаниеОповещения(
		"ПолучитьСвойстваСертификатовНаКлиентеПослеПолученияВсехСертификатовПолучателей", ЭтотОбъект, Контекст));
	
КонецПроцедуры

// Продолжение процедуры ПолучитьСвойстваСертификатовНаКлиенте.
//
// Параметры:
//   Контекст - Структура:
//     * МассивСертификатов - Массив
//
Процедура ПолучитьСвойстваСертификатовНаКлиентеПослеПолученияВсехСертификатовПолучателей(Массив, Контекст) Экспорт
	
	Для каждого Сертификат Из Массив Цикл
		Контекст.МассивСертификатов.Добавить(Сертификат);
	КонецЦикла;
	
	ПолучитьСвойстваСертификатовНаКлиентеПослеПолученияВсех(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ПолучитьСвойстваСертификатовНаКлиенте.
Процедура ПолучитьСвойстваСертификатовНаКлиентеПослеПолученияВсех(Контекст)
	
	ПараметрыДобавленияСвойств = Новый Структура("ТолькоОтпечатки", Контекст.ТолькоОтпечатки);
	ЭлектроннаяПодписьСлужебныйКлиентСервер.ДобавитьСвойстваСертификатов(
		Контекст.Результат.СвойстваСертификатовНаКлиенте,
		Контекст.МассивСертификатов,
		Контекст.БезОтбора,
		ДобавкаВремени(),
		ОбщегоНазначенияКлиент.ДатаСеанса(),
		ПараметрыДобавленияСвойств);
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, Контекст.Результат);
	
КонецПроцедуры

// Только для внутреннего назначения.
Процедура ДобавитьСертификатТолькоДляШифрованияИзФайла(ПараметрыСоздания, МножественныйВыбор = Ложь) Экспорт
	
	Оповещение = Новый ОписаниеОповещения("ДобавитьСертификатТолькоДляШифрованияИзФайлаПослеПомещенияФайлов",
		ЭтотОбъект, ПараметрыСоздания);
	
	ПараметрыЗагрузки = ФайловаяСистемаКлиент.ПараметрыЗагрузкиФайла();
	ПараметрыЗагрузки.Диалог.Заголовок = НСтр("ru = 'Выберите файл сертификата (только для шифрования)'");
	ПараметрыЗагрузки.Диалог.Фильтр = НСтр("ru = 'Сертификат X.509 (*.cer;*.crt)|*.cer;*.crt'")+ "|"
		+ СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Все файлы (%1)|%1'"), ПолучитьМаскуВсеФайлы());
	
	Если МножественныйВыбор Тогда
		ПараметрыЗагрузки.Диалог.МножественныйВыбор = МножественныйВыбор;
		ФайловаяСистемаКлиент.ЗагрузитьФайлы(Оповещение, ПараметрыЗагрузки);
	Иначе
		ФайловаяСистемаКлиент.ЗагрузитьФайл(Оповещение, ПараметрыЗагрузки);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ДобавитьСертификатТолькоДляШифрованияИзФайла.
Процедура ДобавитьСертификатТолькоДляШифрованияИзФайлаПослеПомещенияФайлов(ПомещенныеФайлы, Контекст) Экспорт
	
	Если Не ЗначениеЗаполнено(ПомещенныеФайлы) Тогда
		Возврат;
	КонецЕсли;
	
	Если ТипЗнч(ПомещенныеФайлы) = Тип("Массив") Тогда

		Если ПомещенныеФайлы.Количество() = 1 Тогда
			ДобавитьСертификатТолькоДляШифрованияИзФайлаПослеПомещенияФайла(ПомещенныеФайлы[0].Хранение, Контекст);
			Возврат;
		КонецЕсли;

		ДобавитьСертификатыТолькоДляШифрованияИзФайлаПослеПомещенияФайлов(ПомещенныеФайлы, Контекст);
		Возврат;
		
	КонецЕсли;
	
	ДобавитьСертификатТолькоДляШифрованияИзФайлаПослеПомещенияФайла(ПомещенныеФайлы.Хранение, Контекст);
	
КонецПроцедуры

// Продолжение процедуры ДобавитьСертификатТолькоДляШифрованияИзФайла.
Процедура ДобавитьСертификатТолькоДляШифрованияИзФайлаПослеПомещенияФайла(Адрес, Контекст)
	
	ПараметрыФормы = Новый Структура;
	ПараметрыФормы.Вставить("АдресДанныхСертификата", Адрес);
	ПараметрыФормы.Вставить("ЛичныйСписокПриДобавлении", Контекст.ВЛичныйСписок);
	ПараметрыФормы.Вставить("Организация",               Контекст.Организация);
	
	ОбработчикЗавершения = ?(Контекст.Свойство("ОбработчикЗавершения"), Контекст.ОбработчикЗавершения, Неопределено);
	Форма = ОткрытьФорму("Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования.Форма.ДобавлениеСертификатаДляШифрования",
		ПараметрыФормы, , , , , ОбработчикЗавершения);
	
	Если Форма = Неопределено Тогда
		ПоказатьПредупреждение(,
			НСтр("ru = 'Файл сертификата должен быть в формате DER X.509, операция прервана.'"));
		Возврат;
	КонецЕсли;
	
	Если Не Форма.Открыта() Тогда
		Кнопки = Новый СписокЗначений;
		Кнопки.Добавить("Открыть", НСтр("ru = 'Открыть'"));
		Кнопки.Добавить("Отмена",  НСтр("ru = 'Отмена'"));
		ПоказатьВопрос(
			Новый ОписаниеОповещения("ДобавитьСертификатТолькоДляШифрованияИзФайлаПослеПредупрежденияОСуществующем",
				ЭтотОбъект, Форма.Сертификат),
			НСтр("ru = 'Сертификат уже добавлен.'"), Кнопки);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ДобавитьСертификатТолькоДляШифрованияИзФайла.
Процедура ДобавитьСертификатыТолькоДляШифрованияИзФайлаПослеПомещенияФайлов(ПомещенныеФайлы, Контекст)
	
	ПараметрыФормы = Новый Структура;
	ПараметрыФормы.Вставить("ПомещенныеФайлы", ПомещенныеФайлы);
	ПараметрыФормы.Вставить("Организация",     Контекст.Организация);
	
	ОбработчикЗавершения = ?(Контекст.Свойство("ОбработчикЗавершения"), Контекст.ОбработчикЗавершения, Неопределено);
	ОткрытьФорму("Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования.Форма.ДобавлениеСертификатовДляШифрования",
		ПараметрыФормы, , , , , ОбработчикЗавершения);
	
КонецПроцедуры

// Продолжение процедуры ДобавитьСертификатТолькоДляШифрованияИзФайла.
Процедура ДобавитьСертификатТолькоДляШифрованияИзФайлаПослеПредупрежденияОСуществующем(Ответ, Сертификат) Экспорт
	
	Если Ответ <> "Открыть" Тогда
		Возврат;
	КонецЕсли;
	
	ОткрытьСертификат(Сертификат);
	
КонецПроцедуры

// Только для внутреннего назначения.
Процедура ДобавитьСертификатТолькоДляШифрованияИзКаталога(ПараметрыСоздания)
	
	Оповещение = Новый ОписаниеОповещения("ДобавитьСертификатТолькоДляШифрованияИзКаталогаПослеПодключенияРасширения",
		ЭтотОбъект, ПараметрыСоздания);
		
	ТекстПредложения =  НСтр("ru = 'Для загрузки сертификатов из каталога требуется установить расширение для работы с 1С:Предприятием.'");
	ФайловаяСистемаКлиент.ПодключитьРасширениеДляРаботыСФайлами(Оповещение, ТекстПредложения, Ложь);
		
КонецПроцедуры

// Продолжение процедуры ДобавитьСертификатТолькоДляШифрованияИзКаталога.
Процедура ДобавитьСертификатТолькоДляШифрованияИзКаталогаПослеПодключенияРасширения(Результат, ПараметрыСоздания) Экспорт
	
	Если Результат <> Истина Тогда
		Возврат;
	КонецЕсли;
		
	Оповещение = Новый ОписаниеОповещения("ДобавитьСертификатТолькоДляШифрованияИзФайлаПослеВыбораКаталога",
		ЭтотОбъект, ПараметрыСоздания);
	
	Заголовок = НСтр("ru = 'Выберите каталог файлов сертификатов (только для шифрования)'");
	
	ФайловаяСистемаКлиент.ВыбратьКаталог(Оповещение, Заголовок);
	
КонецПроцедуры

// Продолжение процедуры ДобавитьСертификатТолькоДляШифрованияИзКаталога.
Асинх Процедура ДобавитьСертификатТолькоДляШифрованияИзФайлаПослеВыбораКаталога(ВыбранныйКаталог, Контекст) Экспорт
	
	Если Не ЗначениеЗаполнено(ВыбранныйКаталог) Тогда
		Возврат;
	КонецЕсли;
	
	Оповещение = Новый ОписаниеОповещения("ДобавитьСертификатТолькоДляШифрованияИзФайлаПослеПомещенияФайлов",
		ЭтотОбъект, Контекст);
	
	ОписаниеПередаваемыхФайлов = Новый Массив;
	
	Файлы = Ждать НайтиФайлыАсинх(ВыбранныйКаталог,"*.*", Истина);

	Для Каждого ТекущийФайл Из Файлы Цикл
		Если Ждать ТекущийФайл.ЭтоКаталогАсинх() Тогда
			Продолжить;
		КонецЕсли;
		ОписаниеПередаваемогоФайла = Новый ОписаниеПередаваемогоФайла(ТекущийФайл.ПолноеИмя);
		ОписаниеПередаваемыхФайлов.Добавить(ОписаниеПередаваемогоФайла);
	КонецЦикла;
	
	Если ОписаниеПередаваемыхФайлов.Количество() = 0 Тогда
		ВызватьИсключение НСтр("ru = 'Указанный каталог не содержит файлов.'");
	КонецЕсли;
	
	ПараметрыЗагрузки = ФайловаяСистемаКлиент.ПараметрыЗагрузкиФайла();
	ПараметрыЗагрузки.Интерактивно = Ложь;
	ФайловаяСистемаКлиент.ЗагрузитьФайлы(Оповещение, ПараметрыЗагрузки, ОписаниеПередаваемыхФайлов);
		
КонецПроцедуры

// Продолжение процедуры ПоказатьОшибкуОбращенияКПрограмме.
Процедура ПоказатьОшибкуОбращенияКПрограммеПослеПодключенияРасширения(Подключено, Контекст) Экспорт
	
	Контекст.ПараметрыФормы.Вставить("РасширениеПодключено", Подключено);
	
	ОткрытьФорму("Справочник.ПрограммыЭлектроннойПодписиИШифрования.Форма.ОшибкаОбращенияКПрограмме",
		Контекст.ПараметрыФормы,,,, , Контекст.ОбработкаПродолжения);
	
КонецПроцедуры

// Только для внутреннего использования.
Процедура УстановитьПарольСертификата(СертификатСсылка, Пароль, ПояснениеПароля = Неопределено) Экспорт
	
	ФормаПередачаПараметров().УстановитьПарольСертификата(СертификатСсылка, Пароль, ПояснениеПароля);
	
КонецПроцедуры

// Только для внутреннего использования.
Функция ПарольСертификатаУстановлен(СертификатСсылка) Экспорт
	
	Возврат ФормаПередачаПараметров().ПарольСертификатаУстановлен(СертификатСсылка);
	
КонецФункции

// Только для внутреннего использования.
Процедура ОткрытьНовуюФорму(ВидФормы, КлиентскиеПараметры, СерверныеПараметры, ОбработкаЗавершения) Экспорт
	
	ОписаниеДанных = КлиентскиеПараметры.ОписаниеДанных;
	
	СерверныеПараметры.Вставить("БезПодтверждения", Ложь);
	
	Если СерверныеПараметры.Свойство("ОтборСертификатов")
	   И ТипЗнч(СерверныеПараметры.ОтборСертификатов) = Тип("Массив")
	   И СерверныеПараметры.ОтборСертификатов.Количество() = 1
	   И ОписаниеДанных.Свойство("БезПодтверждения")
	   И ОписаниеДанных.БезПодтверждения Тогда
		
		СерверныеПараметры.Вставить("БезПодтверждения", Истина);
	КонецЕсли;
	
	Если СерверныеПараметры.Свойство("НаборСертификатов")
	   И ОписаниеДанных.Свойство("БезПодтверждения")
	   И ОписаниеДанных.БезПодтверждения Тогда
		
		СерверныеПараметры.Вставить("БезПодтверждения", Истина);
	КонецЕсли;
	
	НастроитьПредставлениеДанных(КлиентскиеПараметры, СерверныеПараметры);
	
	Контекст = Новый Структура;
	Контекст.Вставить("ВидФормы",            ВидФормы);
	Контекст.Вставить("КлиентскиеПараметры", КлиентскиеПараметры);
	Контекст.Вставить("СерверныеПараметры",  СерверныеПараметры);
	Контекст.Вставить("ОбработкаЗавершения", ОбработкаЗавершения);
	
	Если ЭлектроннаяПодписьКлиент.СоздаватьЭлектронныеПодписиНаСервере()
	   И СерверныеПараметры.Свойство("ВыполнятьНаСервере")
	   И СерверныеПараметры.ВыполнятьНаСервере = Истина Тогда
		
		ОткрытьНовуюФормуЗавершение(Новый Массив, Контекст);
	Иначе
		ПолучитьОтпечаткиСертификатовНаКлиенте(Новый ОписаниеОповещения(
			"ОткрытьНовуюФормуЗавершение", ЭтотОбъект, Контекст), ВидФормы = "РасшифровкаДанных");
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ОткрытьНовуюФорму.
Процедура ОткрытьНовуюФормуЗавершение(ОтпечаткиСертификатовНаКлиенте, Контекст) Экспорт
	
	Контекст.СерверныеПараметры.Вставить("ОтпечаткиСертификатовНаКлиенте",
		ОтпечаткиСертификатовНаКлиенте);
	
	ФормаПередачаПараметров().ОткрытьНовуюФорму(
		Контекст.ВидФормы,
		Контекст.СерверныеПараметры,
		Контекст.КлиентскиеПараметры,
		Контекст.ОбработкаЗавершения);
	
КонецПроцедуры

// Только для внутреннего использования.
Процедура ОткрытьФормуОповещенияОНеобходимостиЗаменыСертификата(Параметры) Экспорт
	
	ОткрытьФорму("Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования.Форма.ОповещениеОбОкончанииСрокаДействия",
			Параметры,,,,,,РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс);
		
КонецПроцедуры

// Только для внутреннего использования.
Процедура ОбновитьФормуПередПовторнымИспользованием(Форма, КлиентскиеПараметры) Экспорт
	
	СерверныеПараметры  = Новый Структура;
	НастроитьПредставлениеДанных(КлиентскиеПараметры, СерверныеПараметры);
	
	Форма.ПредставлениеДанных  = СерверныеПараметры.ПредставлениеДанных;
	
КонецПроцедуры

// Только для внутреннего использования.
Процедура НастроитьПредставлениеДанных(КлиентскиеПараметры, СерверныеПараметры) Экспорт
	
	ОписаниеДанных = КлиентскиеПараметры.ОписаниеДанных;
	
	Если ОписаниеДанных.Свойство("СписокПредставлений") Тогда
		СписокПредставлений = ОписаниеДанных.СписокПредставлений;
	Иначе
		СписокПредставлений = Новый Массив;
		
		Если ОписаниеДанных.Свойство("Данные")
		 Или ОписаниеДанных.Свойство("Объект") Тогда
			
			ЗаполнитьСписокПредставлений(СписокПредставлений, ОписаниеДанных);
		Иначе
			Для каждого ЭлементДанных Из ОписаниеДанных.НаборДанных Цикл
				ЗаполнитьСписокПредставлений(СписокПредставлений, ЭлементДанных);
			КонецЦикла;
		КонецЕсли;
	КонецЕсли;
	
	ТекущийСписокПредставлений = Новый СписокЗначений;
	
	Для каждого ЭлементСписка Из СписокПредставлений Цикл
		Если ТипЗнч(ЭлементСписка) = Тип("Строка") Тогда
			Представление = ЭлементСписка.Представление;
			Значение = Неопределено;
		ИначеЕсли ТипЗнч(ЭлементСписка) = Тип("Структура") Тогда
			Представление = ЭлементСписка.Представление;
			Значение = ЭлементСписка.Значение;
		Иначе // Ссылка
			Представление = "";
			Значение = ЭлементСписка.Значение;
		КонецЕсли;
		Если ЗначениеЗаполнено(ЭлементСписка.Представление) Тогда
			Представление = ЭлементСписка.Представление;
		Иначе
			Представление = Строка(ЭлементСписка.Значение);
		КонецЕсли;
		ТекущийСписокПредставлений.Добавить(Значение, Представление);
	КонецЦикла;
	
	Если ТекущийСписокПредставлений.Количество() > 1 Тогда
		СерверныеПараметры.Вставить("ПредставлениеДанныхОткрывается", Истина);
		СерверныеПараметры.Вставить("ПредставлениеДанных", СтрЗаменить(
			ОписаниеДанных.ПредставлениеНабора, "%1", ОписаниеДанных.НаборДанных.Количество()));
	Иначе
		СерверныеПараметры.Вставить("ПредставлениеДанныхОткрывается",
			ТипЗнч(ТекущийСписокПредставлений[0].Значение) = Тип("ОписаниеОповещения")
			Или ЗначениеЗаполнено(ТекущийСписокПредставлений[0].Значение));
		
		СерверныеПараметры.Вставить("ПредставлениеДанных",
			ТекущийСписокПредставлений[0].Представление);
	КонецЕсли;
	
	КлиентскиеПараметры.Вставить("ТекущийСписокПредставлений", ТекущийСписокПредставлений);
	
КонецПроцедуры

// Только для внутреннего использования.
Процедура НачалоВыбораСертификатаПриУстановленномОтборе(Форма) Экспорт
	
	ДоступныеСертификаты = "";
	НедоступныеСертификаты = "";
	
	Текст = НСтр("ru = 'Сертификаты, которые могут быть использованы для этой операции ограничены.'");
	
	Для каждого ЭлементСписка Из Форма.ОтборСертификатов Цикл
		Если Форма.СертификатСписокВыбора.НайтиПоЗначению(ЭлементСписка.Значение) = Неопределено Тогда
			НедоступныеСертификаты = НедоступныеСертификаты + Символы.ПС + Строка(ЭлементСписка.Значение);
		Иначе
			ДоступныеСертификаты = ДоступныеСертификаты + Символы.ПС + Строка(ЭлементСписка.Значение);
		КонецЕсли;
	КонецЦикла;
	
	Если ЗначениеЗаполнено(ДоступныеСертификаты) Тогда
		Заголовок = НСтр("ru = 'Следующие разрешенные сертификаты доступны для выбора:'");
		Текст = Текст + Символы.ПС + Символы.ПС + Заголовок + Символы.ПС + СокрЛП(ДоступныеСертификаты);
	КонецЕсли;
	
	Если ЗначениеЗаполнено(НедоступныеСертификаты) Тогда
		Если ЭлектроннаяПодписьКлиент.СоздаватьЭлектронныеПодписиНаСервере() Тогда
			Если ЗначениеЗаполнено(ДоступныеСертификаты) Тогда
				Заголовок = НСтр("ru = 'Следующие разрешенные сертификаты не установлены ни на компьютере, ни на сервере:'");
			Иначе
				Заголовок = НСтр("ru = 'Ни один из следующих разрешенных сертификатов не установлен ни на компьютере, ни на сервере:'");
			КонецЕсли;
		Иначе
			Если ЗначениеЗаполнено(ДоступныеСертификаты) Тогда
				Заголовок = НСтр("ru = 'Следующие разрешенные сертификаты не установлены на компьютере:'");
			Иначе
				Заголовок = НСтр("ru = 'Ни один из следующих разрешенных сертификатов не установлен на компьютере:'");
			КонецЕсли;
		КонецЕсли;
		Текст = Текст + Символы.ПС + Символы.ПС + Заголовок + Символы.ПС + СокрЛП(НедоступныеСертификаты);
	КонецЕсли;
	
	ПоказатьПредупреждение(, Текст);
	
КонецПроцедуры

// Продолжение процедуры ВыборСертификатаДляПодписанияИлиРасшифровки.
Процедура ВыборСертификатаДляПодписанияИлиРасшифровкиПродолжение(Результат, Контекст) Экспорт
	
	Контекст.СерверныеПараметры.Вставить("СвойстваСертификатовНаКлиенте",
		Результат.СвойстваСертификатовНаКлиенте);
	
	Контекст.СерверныеПараметры.Вставить("ОшибкаПолученияСертификатовНаКлиенте",
		Результат.ОшибкаПолученияСертификатовНаКлиенте);
	
	ФормаПередачаПараметров().ОткрытьНовуюФорму("ВыборСертификатаДляПодписанияИлиРасшифровки",
		Контекст.СерверныеПараметры, , Контекст.ОбработчикЗавершения, Контекст.ВладелецНовойФормы);
	
КонецПроцедуры

// Только для внутреннего использования.
Процедура ПроверитьСертификатСправочника(Сертификат, ДополнительныеПараметры) Экспорт
	
	СерверныеПараметры = Новый Структура;
	СерверныеПараметры.Вставить("ЗаголовокФормы");
	СерверныеПараметры.Вставить("ПроверкаПриВыборе");
	СерверныеПараметры.Вставить("ПараметрыДополнительныхПроверок");
	
	Если ТипЗнч(ДополнительныеПараметры) = Тип("Структура") Тогда
		
		УказанКонтекстДругойОперации = Ложь;
		Если ДополнительныеПараметры.Свойство("КонтекстОперации")
			И ТипЗнч(ДополнительныеПараметры.КонтекстОперации) = Тип("ФормаКлиентскогоПриложения") Тогда
			
			Если Не ДополнительныеПараметры.Свойство("БезПодтверждения") Тогда
				ДополнительныеПараметры.Вставить("БезПодтверждения");
			КонецЕсли;
			
			УказанКонтекстДругойОперации = Истина;
			ДополнительныеПараметры.БезПодтверждения = Истина;
			
		ИначеЕсли ДополнительныеПараметры.Свойство("НеПоказыватьРезультаты") Тогда
			ДополнительныеПараметры.НеПоказыватьРезультаты = Ложь;
		КонецЕсли;
		
		КлиентскиеПараметры = ДополнительныеПараметры;
		Если УказанКонтекстДругойОперации Тогда
			КлиентскиеПараметры.Вставить("УказанКонтекстДругойОперации");
		КонецЕсли;
		
		ЗаполнитьЗначенияСвойств(СерверныеПараметры, ДополнительныеПараметры);
		
	Иначе
		КлиентскиеПараметры = Новый Структура;
	КонецЕсли;
	
	СерверныеПараметры.Вставить("Сертификат", Сертификат);
	
	ВладелецФормы = Неопределено;
	КлиентскиеПараметры.Свойство("ВладелецФормы", ВладелецФормы);
	
	ОбработкаЗавершения = Неопределено;
	КлиентскиеПараметры.Свойство("ОбработкаЗавершения", ОбработкаЗавершения);
	
	ФормаПередачаПараметров().ОткрытьНовуюФорму("ПроверкаСертификата",
		СерверныеПараметры, КлиентскиеПараметры, ОбработкаЗавершения, ВладелецФормы);
	
КонецПроцедуры

// Только для внутреннего использования.
Процедура СтандартноеЗавершение(Успех, КлиентскиеПараметры) Экспорт
	
	КлиентскиеПараметры.ОписаниеДанных.Вставить("Успех", Успех = Истина);
	КлиентскиеПараметры.ОписаниеДанных.Вставить("Отказ", Успех = Неопределено);
	
	Если КлиентскиеПараметры.ОбработкаРезультата <> Неопределено Тогда
		
		ОбработкаРезультата = КлиентскиеПараметры.ОбработкаРезультата;
		КлиентскиеПараметры.ОбработкаРезультата = Неопределено;
		ВыполнитьОбработкуОповещения(ОбработкаРезультата, КлиентскиеПараметры.ОписаниеДанных);
		
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.ДобавитьПодписьИзФайла.
Процедура ДобавитьПодписьИзФайлаПослеСозданияМенеджераКриптографии(Результат, Контекст) Экспорт
	
	Если Контекст.ПроверитьМенеджерКриптографииНаКлиенте
	   И ТипЗнч(Результат) <> Тип("МенеджерКриптографии") Тогда
		
		ПоказатьОшибкуОбращенияКПрограмме(
			НСтр("ru = 'Требуется программа электронной подписи и шифрования'"),
			"", Результат, Контекст.ФормаДобавления.МенеджерКриптографииНаСервереОписаниеОшибки);
	Иначе
		Контекст.ФормаДобавления.Открыть();
		Если Контекст.ФормаДобавления.Открыта() Тогда
			Возврат;
		КонецЕсли;
	КонецЕсли;
	
	Если Контекст.ОбработкаРезультата <> Неопределено Тогда
		ВыполнитьОбработкуОповещения(Контекст.ОбработкаРезультата, Контекст.ОписаниеДанных);
	КонецЕсли;
	
КонецПроцедуры

// Предлагает пользователю выбрать подписи для сохранения вместе с данными объекта.
//
// Общий подход к обработке значений свойств с типом ОписаниеОповещения в параметре ОписаниеДанных.
//  При выполнении обработки оповещения в нее передается структура параметров, в которой всегда есть
//  свойство "Оповещение" типа ОписаниеОповещения, обработку которого нужно выполнить для продолжения.
//  Кроме того, в структуре всегда есть свойство ОписаниеДанных, полученное при вызове процедуры.
//  При вызове оповещения в качестве значения должна передаваться структура. Если в процессе асинхронного
//  выполнения возникает ошибка, тогда в эту структуру нужно вставить свойство ОписаниеОшибки типа Строка.
// 
// Параметры:
//  ОписаниеДанных - Структура:
//    * ЗаголовокДанных     - Строка - заголовок элемента данных, например Файл.
//    * ПоказатьКомментарий - Булево - (необязательный) - разрешает ввод комментария в форме
//                              добавления подписей. Если не указан, значит Ложь.
//    * Представление      - ЛюбаяСсылка
//                         - Строка - (необязательный), если не указан, тогда
//                                представление вычисляется по значению свойства Объект.
//    * Объект             - ЛюбаяСсылка - ссылка на объект с табличной частью ЭлектронныеПодписи,
//                              из которой нужно получить список подписей.
//                         - Строка - адрес временного хранилища массива подписей с составом свойств,
//                              как возвращает процедура ДобавитьПодписьИзФайла.
//    * Данные             - ОписаниеОповещения - обработчик сохранения данных и получения полного имени
//                              файла с путем (после его сохранения), возвращаемое в свойстве ПолноеИмяФайла
//                              типа Строка для сохранения электронных подписей (смотри выше общий подход).
//                              Если расширение для работы с 1С:Предприятием не подключено, то нужно вернуть
//                              имя файла без пути.
//                              Если свойство не будет вставлено или заполнено - это считается отказом
//                              от продолжения и будет вызвана ОбработкаРезультата с результатом Ложь.
//
//                              Для пакетного запроса разрешений у пользователя веб-клиента на сохранение файла данных
//                              и подписей, нужно вставить параметр ОбработкаЗапросаРазрешений типа ОписаниеОповещения.
//                              В процедуру будет передана Структура:
//                                # Вызовы               - Массив - с описанием вызовов для сохранения подписей.
//                                # ОбработкаПродолжения - ОписаниеОповещения - оповещение, которое нужно выполнить
//                                                         после запроса разрешений, - параметры процедуры как у
//                                                         оповещения для метода НачатьЗапросРазрешенияПользователя.
//                                                         Если разрешение не получено, значит все отменено.
//
//  ОбработкаРезультата - ОписаниеОповещения - в результат передается параметр:
//    Булево - Истина, если все прошло успешно.
//
Процедура СохранитьДанныеВместеСПодписью(ОписаниеДанных, ОбработкаРезультата = Неопределено) Экспорт
	
	Контекст = Новый Структура;
	Контекст.Вставить("ОписаниеДанных", ОписаниеДанных);
	Контекст.Вставить("ОбработкаРезультата", ОбработкаРезультата);
	
	ПерсональныеНастройки = ЭлектроннаяПодписьКлиент.ПерсональныеНастройки();
	СохранятьВсеПодписи = ПерсональныеНастройки.ДействияПриСохраненииСЭП = "СохранятьВсеПодписи";
	СохранятьСертификатВместеСПодписью = ПерсональныеНастройки.СохранятьСертификатВместеСПодписью;
	
	СерверныеПараметры = Новый Структура;
	СерверныеПараметры.Вставить("ЗаголовокДанных",     НСтр("ru = 'Данные'"));
	СерверныеПараметры.Вставить("ПоказатьКомментарий", Ложь);
	ЗаполнитьЗначенияСвойств(СерверныеПараметры, ОписаниеДанных);
	
	Контекст.Вставить("СохранятьСертификатВместеСПодписью", СохранятьСертификатВместеСПодписью);
	
	СерверныеПараметры.Вставить("СохранятьВсеПодписи", СохранятьВсеПодписи);
	СерверныеПараметры.Вставить("Объект", ОписаниеДанных.Объект);
	
	КлиентскиеПараметры = Новый Структура;
	КлиентскиеПараметры.Вставить("ОписаниеДанных", ОписаниеДанных);
	НастроитьПредставлениеДанных(КлиентскиеПараметры, СерверныеПараметры);
	
	ФормаСохранения = ОткрытьФорму("ОбщаяФорма.СохранениеВместеСЭлектроннойПодписью", СерверныеПараметры,,,,,
		Новый ОписаниеОповещения("СохранитьДанныеВместеСПодписьюПослеВыбораПодписей", ЭтотОбъект, Контекст));
	
	Завершить = Ложь;
	Контекст.Вставить("Форма", ФормаСохранения);
	
	Если ФормаСохранения = Неопределено Тогда
		Завершить = Истина;
	Иначе
		ФормаСохранения.КлиентскиеПараметры = КлиентскиеПараметры;
		
		Если СохранятьВсеПодписи Тогда
			СохранитьДанныеВместеСПодписьюПослеВыбораПодписей(ФормаСохранения.ТаблицаПодписей, Контекст);
			Возврат;
			
		ИначеЕсли Не ФормаСохранения.Открыта() Тогда
			Завершить = Истина;
		КонецЕсли;
	КонецЕсли;
	
	Если Завершить И Контекст.ОбработкаРезультата <> Неопределено Тогда
		ВыполнитьОбработкуОповещения(Контекст.ОбработкаРезультата, Ложь);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.СохранитьДанныеВместеСПодписью.
Процедура СохранитьДанныеВместеСПодписьюПослеВыбораПодписей(КоллекцияПодписей, Контекст) Экспорт
	
	Если ТипЗнч(КоллекцияПодписей) <> Тип("ДанныеФормыКоллекция") Тогда
		Если Контекст.ОбработкаРезультата <> Неопределено Тогда
			ВыполнитьОбработкуОповещения(Контекст.ОбработкаРезультата, Ложь);
		КонецЕсли;
		Возврат;
	КонецЕсли;
	
	Контекст.Вставить("КоллекцияПодписей", КоллекцияПодписей);
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОписаниеДанных", Контекст.ОписаниеДанных);
	ПараметрыВыполнения.Вставить("Оповещение", Новый ОписаниеОповещения(
		"СохранитьДанныеВместеСПодписьюПослеСохраненияФайлаДанных", ЭтотОбъект, Контекст));
	
	Попытка
		ВыполнитьОбработкуОповещения(Контекст.ОписаниеДанных.Данные, ПараметрыВыполнения);
	Исключение
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		СохранитьДанныеВместеСПодписьюПослеСохраненияФайлаДанных(
			Новый Структура("ОписаниеОшибки", ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке)), Контекст);
	КонецПопытки;
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.СохранитьДанныеВместеСПодписью.
Процедура СохранитьДанныеВместеСПодписьюПослеСохраненияФайлаДанных(Результат, Контекст) Экспорт
	
	Если Результат.Свойство("ОписаниеОшибки") Тогда
		Ошибка = Новый Структура("ОписаниеОшибки",
			НСтр("ru = 'Не удалось записать файл по причине:'") + Символы.ПС + Результат.ОписаниеОшибки);
		
		ПоказатьОшибкуОбращенияКПрограмме(
			НСтр("ru = 'Не удалось сохранить подписи вместе с файлом'"), "", Ошибка, Новый Структура);
		Возврат;
		
	ИначеЕсли Не Результат.Свойство("ПолноеИмяФайла")
		Или ТипЗнч(Результат.ПолноеИмяФайла) <> Тип("Строка")
		Или ПустаяСтрока(Результат.ПолноеИмяФайла) Тогда
		
		Если Контекст.ОбработкаРезультата <> Неопределено Тогда
			ВыполнитьОбработкуОповещения(Контекст.ОбработкаРезультата, Ложь);
		КонецЕсли;
		Возврат;
	КонецЕсли;
	
	Если Результат.Свойство("ОбработкаЗапросаРазрешений") Тогда
		Контекст.Вставить("ОбработкаЗапросаРазрешений", Результат.ОбработкаЗапросаРазрешений);
	КонецЕсли;
	
	Контекст.Вставить("ПолноеИмяФайла", Результат.ПолноеИмяФайла);
	Контекст.Вставить("СоставИмениФайлаДанных",
		ОбщегоНазначенияКлиентСервер.РазложитьПолноеИмяФайла(Контекст.ПолноеИмяФайла));
	
	ФайловаяСистемаКлиент.ПодключитьРасширениеДляРаботыСФайлами(Новый ОписаниеОповещения(
		"СохранитьДанныеВместеСПодписьюПослеПодключенияРасширенияРаботыСФайлами", ЭтотОбъект, Контекст));
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.СохранитьДанныеВместеСПодписью.
Процедура СохранитьДанныеВместеСПодписьюПослеПодключенияРасширенияРаботыСФайлами(Подключено, Контекст) Экспорт
	
	Контекст.Вставить("Подключено", Подключено);
	
	Контекст.Вставить("РасширениеДляФайловПодписи",
	ЭлектроннаяПодписьКлиент.ПерсональныеНастройки().РасширениеДляФайловПодписи);
	
	Если Контекст.Подключено Тогда
		Контекст.Вставить("ПолучаемыеФайлы", Новый Массив);
		Если ЗначениеЗаполнено(Контекст.СоставИмениФайлаДанных.Путь) Тогда
			Контекст.Вставить("ПутьКФайлам", ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(
				Контекст.СоставИмениФайлаДанных.Путь));
		Иначе
			Контекст.Вставить("ПутьКФайлам", "");
		КонецЕсли;
	КонецЕсли;
	
	Контекст.Вставить("ИменаФайлов", Новый Соответствие);
	Контекст.ИменаФайлов.Вставить(Контекст.СоставИмениФайлаДанных.Имя, Истина);
	
	Контекст.Вставить("Индекс", -1);
	
	СохранитьДанныеВместеСПодписьюЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.СохранитьДанныеВместеСПодписью.
// 
// Параметры:
//  Контекст - Структура:
//   * Индекс - Число
//
Процедура СохранитьДанныеВместеСПодписьюЦиклНачало(Контекст)
	
	Если Контекст.КоллекцияПодписей.Количество() <= Контекст.Индекс + 1 Тогда
		СохранитьДанныеВместеСПодписьюПослеЦикла(Контекст);
		Возврат;
	КонецЕсли;
	Контекст.Индекс = Контекст.Индекс + 1;
	Контекст.Вставить("ОписаниеПодписи", Контекст.КоллекцияПодписей[Контекст.Индекс]);
	
	Если Не Контекст.ОписаниеПодписи.Пометка Тогда
		СохранитьДанныеВместеСПодписьюЦиклНачало(Контекст);
		Возврат;
	КонецЕсли;
	
	Контекст.Вставить("ИмяФайлаПодписи", Контекст.ОписаниеПодписи.ИмяФайлаПодписи);
	
	Если ПустаяСтрока(Контекст.ИмяФайлаПодписи) Тогда 
		Контекст.ИмяФайлаПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.ИмяФайлаПодписи(Контекст.СоставИмениФайлаДанных.ИмяБезРасширения,
			Строка(Контекст.ОписаниеПодписи.КомуВыданСертификат), Контекст.РасширениеДляФайловПодписи);
	Иначе
		Если Не ОбщегоНазначенияКлиент.ЭтоWindowsКлиент() И СтрДлина(Контекст.ИмяФайлаПодписи) > 127 Тогда
			СоставИмениФайлаПодписи = ОбщегоНазначенияКлиентСервер.РазложитьПолноеИмяФайла(Контекст.ИмяФайлаПодписи);
			Контекст.ИмяФайлаПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.ИмяФайлаПодписи(
				СоставИмениФайлаПодписи.ИмяБезРасширения,"", СоставИмениФайлаПодписи.Расширение, Ложь);
		Иначе
			Контекст.ИмяФайлаПодписи = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыВИмениФайла(Контекст.ИмяФайлаПодписи);
		КонецЕсли;
	КонецЕсли;
	
	СоставИмениФайлаПодписи = ОбщегоНазначенияКлиентСервер.РазложитьПолноеИмяФайла(Контекст.ИмяФайлаПодписи);
	Контекст.Вставить("ИмяФайлаПодписиБезРасширения", СоставИмениФайлаПодписи.ИмяБезРасширения);
	
	Контекст.Вставить("Счетчик", 1);
	
	СохранитьДанныеВместеСПодписьюЦиклВнутреннийЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.СохранитьДанныеВместеСПодписью.
Процедура СохранитьДанныеВместеСПодписьюЦиклВнутреннийЦиклНачало(Контекст)
	
	Контекст.Счетчик = Контекст.Счетчик + 1;
	
	Если Контекст.Подключено Тогда
		Контекст.Вставить("ПолноеИмяФайлаПодписи", Контекст.ПутьКФайлам + Контекст.ИмяФайлаПодписи);
	Иначе
		Контекст.Вставить("ПолноеИмяФайлаПодписи", Контекст.ИмяФайлаПодписи);
	КонецЕсли;
	
	Если Контекст.ИменаФайлов[Контекст.ИмяФайлаПодписи] <> Неопределено Тогда
		СохранитьДанныеВместеСПодписьюЦиклВнутреннийЦиклПослеПроверкиСуществованияФайла(Истина, Контекст);
		
	ИначеЕсли Контекст.Подключено Тогда
		Файл = Новый Файл(Контекст.ПолноеИмяФайлаПодписи);
		Файл.НачатьПроверкуСуществования(Новый ОписаниеОповещения(
			"СохранитьДанныеВместеСПодписьюЦиклВнутреннийЦиклПослеПроверкиСуществованияФайла", ЭтотОбъект, Контекст));
	Иначе
		СохранитьДанныеВместеСПодписьюЦиклВнутреннийЦиклПослеПроверкиСуществованияФайла(Ложь, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.СохранитьДанныеВместеСПодписью.
Процедура СохранитьДанныеВместеСПодписьюЦиклВнутреннийЦиклПослеПроверкиСуществованияФайла(Существует, Контекст) Экспорт
	
	Если Не Существует Тогда
		СохранитьДанныеВместеСПодписьюЦиклПослеВнутреннегоЦикла(Контекст);
		Возврат;
	КонецЕсли;
	
	Контекст.ИмяФайлаПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.ИмяФайлаПодписи(Контекст.ИмяФайлаПодписиБезРасширения,
		"(" + Строка(Контекст.Счетчик) + ")", Контекст.РасширениеДляФайловПодписи, Ложь);
	
	СохранитьДанныеВместеСПодписьюЦиклВнутреннийЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.СохранитьДанныеВместеСПодписью.
// 
// Параметры:
//  Контекст - Структура:
//   * ПолучаемыеФайлы - Массив
//
Процедура СохранитьДанныеВместеСПодписьюЦиклПослеВнутреннегоЦикла(Контекст)
	
	СоставИмениФайлаПодписи = ОбщегоНазначенияКлиентСервер.РазложитьПолноеИмяФайла(Контекст.ПолноеИмяФайлаПодписи);
	Контекст.ИменаФайлов.Вставить(СоставИмениФайлаПодписи.Имя, Ложь);
	
	Если Контекст.Подключено Тогда
		Описание = Новый ОписаниеПередаваемогоФайла(СоставИмениФайлаПодписи.Имя, Контекст.ОписаниеПодписи.АдресПодписи);
		Контекст.ПолучаемыеФайлы.Добавить(Описание);
		СохранитьДанныеВместеСПодписьюЦиклПослеСохраненияПодписи(Неопределено, Контекст);
	Иначе
		// Сохранение файла из программы на компьютер.
		ФайловаяСистемаКлиент.СохранитьФайл(
			Новый ОписаниеОповещения("СохранитьДанныеВместеСПодписьюЦиклПослеСохраненияПодписи", ЭтотОбъект, Контекст),
			Контекст.ОписаниеПодписи.АдресПодписи, СоставИмениФайлаПодписи.Имя);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.СохранитьДанныеВместеСПодписью.
Процедура СохранитьДанныеВместеСПодписьюЦиклПослеСохраненияПодписи(Результат, Контекст) Экспорт
	
	Если Контекст.СохранятьСертификатВместеСПодписью Тогда
		СохранитьДанныеСертификатаВместеСПодписьюЦиклНачало(Контекст);
	Иначе
		СохранитьДанныеВместеСПодписьюЦиклНачало(Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.СохранитьДанныеВместеСПодписью.
Процедура СохранитьДанныеСертификатаВместеСПодписьюЦиклВнутреннийЦиклНачало(Контекст)
	
	Если Контекст.Подключено Тогда
		Контекст.Вставить("ПолноеИмяФайлаСертификата", Контекст.ПутьКФайлам + Контекст.ИмяФайлаСертификата);
	Иначе
		Контекст.Вставить("ПолноеИмяФайлаСертификата", Контекст.ИмяФайлаСертификата);
	КонецЕсли;
	
	Если Контекст.ИменаФайлов[Контекст.ИмяФайлаСертификата] <> Неопределено Тогда
		СохранитьДанныеСертификатаВместеСПодписьюЦиклВнутреннийЦиклПослеПроверкиСуществованияФайла(Истина, Контекст);
		
	ИначеЕсли Контекст.Подключено Тогда
		Файл = Новый Файл(Контекст.ПолноеИмяФайлаСертификата);
		Файл.НачатьПроверкуСуществования(Новый ОписаниеОповещения(
			"СохранитьДанныеСертификатаВместеСПодписьюЦиклВнутреннийЦиклПослеПроверкиСуществованияФайла", ЭтотОбъект, Контекст));
	Иначе
		СохранитьДанныеСертификатаВместеСПодписьюЦиклВнутреннийЦиклПослеПроверкиСуществованияФайла(Ложь, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.СохранитьДанныеВместеСПодписью.
Процедура СохранитьДанныеСертификатаВместеСПодписьюЦиклВнутреннийЦиклПослеПроверкиСуществованияФайла(Существует, Контекст) Экспорт
	
	Если Не Существует Тогда
		СохранитьДанныеСертификатаВместеСПодписьюЦиклПослеВнутреннегоЦикла(Контекст);
		Возврат;
	КонецЕсли;
	
	Контекст.ИмяФайлаСертификата = ЭлектроннаяПодписьСлужебныйКлиентСервер.ИмяФайлаСертификата(Контекст.ИмяФайлаСертификатаБезРасширения,
		"(" + Строка(Контекст.Счетчик) + ")", Контекст.ОписаниеПодписи.РасширениеСертификата, Ложь);
	
	СохранитьДанныеСертификатаВместеСПодписьюЦиклВнутреннийЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.СохранитьДанныеВместеСПодписью.
Процедура СохранитьДанныеСертификатаВместеСПодписьюЦиклНачало(Контекст)
	
	Контекст.Вставить("ИмяФайлаСертификата", "");
	
	Контекст.ИмяФайлаСертификата = ЭлектроннаяПодписьСлужебныйКлиентСервер.ИмяФайлаСертификата(Контекст.СоставИмениФайлаДанных.ИмяБезРасширения,
		Строка(Контекст.ОписаниеПодписи.КомуВыданСертификат), Контекст.ОписаниеПодписи.РасширениеСертификата);
	
	СоставИмениФайлаСертификата  = ОбщегоНазначенияКлиентСервер.РазложитьПолноеИмяФайла(Контекст.ИмяФайлаСертификата);
	Контекст.Вставить("ИмяФайлаСертификатаБезРасширения", СоставИмениФайлаСертификата.ИмяБезРасширения);
	
	СохранитьДанныеСертификатаВместеСПодписьюЦиклВнутреннийЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.СохранитьДанныеВместеСПодписью.
// 
// Параметры:
//  Контекст - Структура:
//   * ПолучаемыеФайлы - Массив
//
Процедура СохранитьДанныеСертификатаВместеСПодписьюЦиклПослеВнутреннегоЦикла(Контекст)
	
	СоставИмениФайлаСертификата = ОбщегоНазначенияКлиентСервер.РазложитьПолноеИмяФайла(Контекст.ПолноеИмяФайлаСертификата);
	Контекст.ИменаФайлов.Вставить(СоставИмениФайлаСертификата.Имя, Ложь);
	
	Если Контекст.Подключено Тогда
		Описание = Новый ОписаниеПередаваемогоФайла(СоставИмениФайлаСертификата.Имя, Контекст.ОписаниеПодписи.АдресСертификата);
		Контекст.ПолучаемыеФайлы.Добавить(Описание);
		СохранитьДанныеВместеСПодписьюЦиклНачало(Контекст);
	Иначе
		// Сохранение файла из программы на компьютер.
		ФайловаяСистемаКлиент.СохранитьФайл(
			Новый ОписаниеОповещения("СохранитьДанныеСертификатаВместеСПодписьюЦиклПослеСохраненияСертификата", ЭтотОбъект, Контекст),
			Контекст.ОписаниеПодписи.АдресСертификата, СоставИмениФайлаСертификата.Имя);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.СохранитьДанныеВместеСПодписью.
Процедура СохранитьДанныеСертификатаВместеСПодписьюЦиклПослеСохраненияСертификата(Результат, Контекст) Экспорт
	
	СохранитьДанныеВместеСПодписьюЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.СохранитьДанныеВместеСПодписью.
Процедура СохранитьДанныеВместеСПодписьюПослеЦикла(Контекст)
	
	Если Не Контекст.Подключено Тогда
		Если Контекст.ОбработкаРезультата <> Неопределено Тогда
			ВыполнитьОбработкуОповещения(Контекст.ОбработкаРезультата, Истина);
		КонецЕсли;
		Возврат;
	КонецЕсли;
	
	// Сохранение файла из программы на компьютер.
	Если Контекст.ПолучаемыеФайлы.Количество() > 0 Тогда
		Контекст.Вставить("ПолучаемыеФайлы", Контекст.ПолучаемыеФайлы);
		
		Вызовы = Новый Массив;
		Вызов = Новый Массив;
		Вызов.Добавить("НачатьПолучениеФайлов");
		Вызов.Добавить(Контекст.ПолучаемыеФайлы);
		Вызов.Добавить(Контекст.ПутьКФайлам);
		Вызов.Добавить(Ложь);
		Вызовы.Добавить(Вызов);
		
		ОбработкаПродолжения = Новый ОписаниеОповещения(
			"СохранитьДанныеВместеСПодписьюПослеПолученияРазрешений", ЭтотОбъект, Контекст);
		
		Если Контекст.Свойство("ОбработкаЗапросаРазрешений") Тогда
			ПараметрыВыполнения = Новый Структура;
			ПараметрыВыполнения.Вставить("Вызовы", Вызовы);
			ПараметрыВыполнения.Вставить("ОбработкаПродолжения", ОбработкаПродолжения);
			ВыполнитьОбработкуОповещения(Контекст.ОбработкаЗапросаРазрешений, ПараметрыВыполнения);
		Иначе
			НачатьЗапросРазрешенияПользователя(ОбработкаПродолжения, Вызовы);
		КонецЕсли;
	Иначе
		СохранитьДанныеВместеСПодписьюПослеПолученияРазрешений(Ложь, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.СохранитьДанныеВместеСПодписью.
Процедура СохранитьДанныеВместеСПодписьюПослеПолученияРазрешений(РазрешенияПолучены, Контекст) Экспорт
	
	Если Не РазрешенияПолучены
	   И Контекст.ПолучаемыеФайлы.Количество() > 0
	   И Контекст.Свойство("ОбработкаЗапросаРазрешений") Тогда
		
		// Файл данных не был получен - отчет не требуется.
		Если Контекст.ОбработкаРезультата <> Неопределено Тогда
			ВыполнитьОбработкуОповещения(Контекст.ОбработкаРезультата, Ложь);
		КонецЕсли;
		
	ИначеЕсли РазрешенияПолучены Тогда
		
		ПараметрыСохранения = ФайловаяСистемаКлиент.ПараметрыСохраненияФайлов();
		ПараметрыСохранения.Интерактивно = Не ЗначениеЗаполнено(Контекст.ПутьКФайлам);
		ПараметрыСохранения.Диалог.Каталог = Контекст.ПутьКФайлам;
		ФайловаяСистемаКлиент.СохранитьФайлы(Новый ОписаниеОповещения(
				"СохранитьДанныеВместеСПодписьюПослеПолученияФайлов", ЭтотОбъект, Контекст), 
			Контекст.ПолучаемыеФайлы, ПараметрыСохранения);
	Иначе
		СохранитьДанныеВместеСПодписьюПослеПолученияФайлов(Неопределено, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.СохранитьДанныеВместеСПодписью.
//
// Параметры:
//   ПолученныеФайлы - Массив из ОписаниеПередаваемогоФайла
//
Процедура СохранитьДанныеВместеСПодписьюПослеПолученияФайлов(ПолученныеФайлы, Контекст) Экспорт
	
	ИменаПолученныхФайлов = Новый Соответствие;
	ИменаПолученныхФайлов.Вставить(Контекст.СоставИмениФайлаДанных.Имя, Истина);
	
	Если ТипЗнч(ПолученныеФайлы) = Тип("Массив") Тогда
		Для каждого ПолученныйФайл Из ПолученныеФайлы Цикл
			СоставИмениФайлаПодписи = ОбщегоНазначенияКлиентСервер.РазложитьПолноеИмяФайла(ПолученныйФайл.ПолноеИмя);
			ИменаПолученныхФайлов.Вставить(СоставИмениФайлаПодписи.Имя, Истина);
			Если Не ЗначениеЗаполнено(Контекст.ПутьКФайлам) Тогда
				Контекст.ПутьКФайлам = СоставИмениФайлаПодписи.Путь;
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	
	Текст = НСтр("ru = 'Папка с файлами:'") + Символы.ПС
		+ Контекст.ПутьКФайлам + Символы.ПС + Символы.ПС
		+ НСтр("ru = 'Файлы:'") + Символы.ПС;
	
	Для Каждого КлючИЗначение Из ИменаПолученныхФайлов Цикл
		Текст = Текст + КлючИЗначение.Ключ + Символы.ПС;
	КонецЦикла;
	
	ПараметрыФормы = Новый Структура;
	ПараметрыФормы.Вставить("Текст", Текст);
	Если Не ЗначениеЗаполнено(Контекст.СоставИмениФайлаДанных.Путь) Тогда
		ПараметрыФормы.Вставить("КаталогСФайлами", Контекст.ПутьКФайлам);
	Иначе
		ПараметрыФормы.Вставить("КаталогСФайлами", Контекст.СоставИмениФайлаДанных.Путь);
	КонецЕсли;
		
	ОткрытьФорму("ОбщаяФорма.ОтчетОСохраненииФайловЭлектронныхПодписей", ПараметрыФормы,,,,,
		Новый ОписаниеОповещения("СохранитьДанныеВместеСПодписьюПослеЗакрытияОтчета", ЭтотОбъект, Контекст));
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.СохранитьДанныеВместеСПодписью.
Процедура СохранитьДанныеВместеСПодписьюПослеЗакрытияОтчета(Результат, Контекст) Экспорт
	
	Если Контекст.ОбработкаРезультата <> Неопределено Тогда
		ВыполнитьОбработкуОповещения(Контекст.ОбработкаРезультата, Истина);
	КонецЕсли;
	
КонецПроцедуры

// Только для внутреннего использования.
Процедура ОткрытьИнструкциюПоРаботеСПрограммами() Экспорт
	
	Раздел = "БухгалтерскийИНалоговыйУчет";
	ЭлектроннаяПодписьКлиентПереопределяемый.ПриОпределенииРазделаСтатьиНаИТС(Раздел);
	
	НавигационнаяСсылка = "";
	ЭлектроннаяПодписьКлиентСерверЛокализация.ПриОпределенииСсылкиНаИнструкциюПоРаботеСПрограммами(
		Раздел, НавигационнаяСсылка);
	
	Если Не ПустаяСтрока(НавигационнаяСсылка) Тогда
		ФайловаяСистемаКлиент.ОткрытьНавигационнуюСсылку(НавигационнаяСсылка);
	КонецЕсли;
	
КонецПроцедуры

// См. ЭлектроннаяПодписьКлиент.УстановитьРасширение
Процедура УстановитьРасширение(БезВопроса, ОбработчикРезультата = Неопределено, ТекстВопроса = "", ЗаголовокВопроса = "") Экспорт
	
	Контекст = Новый Структура;
	Контекст.Вставить("Оповещение",       ОбработчикРезультата);
	Контекст.Вставить("ТекстВопроса",     ТекстВопроса);
	Контекст.Вставить("ЗаголовокВопроса", ЗаголовокВопроса);
	Контекст.Вставить("БезВопроса",       БезВопроса);
	
	НачатьПодключениеРасширенияРаботыСКриптографией(Новый ОписаниеОповещения(
		"УстановитьРасширениеПослеПроверкиПодключенияРасширенияРаботыСКриптографией", ЭтотОбъект, Контекст));
	
КонецПроцедуры

// Продолжение процедуры УстановитьРасширение.
Процедура УстановитьРасширениеПослеПроверкиПодключенияРасширенияРаботыСКриптографией(Подключено, Контекст) Экспорт
	
	Если Подключено Тогда
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Истина);
		Возврат;
	КонецЕсли;
	
	НачатьПодключениеРасширенияРаботыСКриптографией(Новый ОписаниеОповещения(
		"УстановитьРасширениеПослеПодключенияРасширенияРаботыСКриптографией", ЭтотОбъект, Контекст));
	
КонецПроцедуры

// Продолжение процедуры УстановитьРасширение.
Процедура УстановитьРасширениеПослеПодключенияРасширенияРаботыСКриптографией(Подключено, Контекст) Экспорт
	
	Если Подключено Тогда
		Если Контекст.Оповещение <> Неопределено Тогда
			ВыполнитьОбработкуОповещения(Контекст.Оповещение, Истина);
		КонецЕсли;
		Возврат;
	КонецЕсли;
	
	Обработчик = Новый ОписаниеОповещения("УстановитьРасширениеПослеОтвета", ЭтотОбъект, Контекст);
	
	Если Контекст.БезВопроса Тогда
		ВыполнитьОбработкуОповещения(Обработчик, КодВозвратаДиалога.Да);
		Возврат;
	КонецЕсли;
	
	ПараметрыФормы = Новый Структура;
	ПараметрыФормы.Вставить("ЗаголовокВопроса", Контекст.ЗаголовокВопроса);
	ПараметрыФормы.Вставить("ТекстВопроса",     Контекст.ТекстВопроса);
	
	ОткрытьФорму("ОбщаяФорма.ВопросОбУстановкеРасширенияРаботыСКриптографией",
		ПараметрыФормы,,,,, Обработчик);
	
КонецПроцедуры

// Продолжение процедуры УстановитьРасширение.
Процедура УстановитьРасширениеПослеОтвета(Ответ, Контекст) Экспорт
	
	Если Ответ = КодВозвратаДиалога.Да Тогда
		НачатьУстановкуРасширенияРаботыСКриптографией(Новый ОписаниеОповещения(
			"УстановитьРасширениеПослеУстановкиРасширенияРаботыСКриптографией", ЭтотОбъект, Контекст));
	Иначе
		Если Контекст.Оповещение <> Неопределено Тогда
			ВыполнитьОбработкуОповещения(Контекст.Оповещение, Неопределено);
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры УстановитьРасширение.
Процедура УстановитьРасширениеПослеУстановкиРасширенияРаботыСКриптографией(Контекст) Экспорт
	
	НачатьПодключениеРасширенияРаботыСКриптографией(Новый ОписаниеОповещения(
		"УстановитьРасширениеПослеПодключенияУстановленногоРасширенияРаботыСКриптографией", ЭтотОбъект, Контекст));
	
КонецПроцедуры

// Продолжение процедуры УстановитьРасширение.
Процедура УстановитьРасширениеПослеПодключенияУстановленногоРасширенияРаботыСКриптографией(Подключено, Контекст) Экспорт
	
	Если Подключено Тогда
		Оповестить("Установка_РасширениеРаботыСКриптографией");
	КонецЕсли;
	
	Если Контекст.Оповещение <> Неопределено Тогда
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Подключено);
	КонецЕсли;
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Общие процедуры и функции управляемых форм.

// Только для внутреннего использования.
Процедура ПродолжитьОткрытиеНачало(Оповещение, Форма, КлиентскиеПараметры, Шифрование = Ложь, Расшифровка = Ложь) Экспорт
	
	Если Не Шифрование Тогда
		ВходныеПараметры = Неопределено;
		КлиентскиеПараметры.ОписаниеДанных.Свойство("ПараметрыДополнительныхДействий", ВходныеПараметры);
		ВыходныеПараметры = Форма.ВыходныеПараметрыДополнительныхДействий;
		Форма.ВыходныеПараметрыДополнительныхДействий = Неопределено;
		ЭлектроннаяПодписьКлиентПереопределяемый.ПередНачаломОперации(
			?(Расшифровка, "Расшифровка", "Подписание"), ВходныеПараметры, ВыходныеПараметры);
	КонецЕсли;
	
	Контекст = Новый Структура;
	Контекст.Вставить("Оповещение", Оповещение);
	Контекст.Вставить("ОшибкаНаСервере", Новый Структура);
	
	Если ЭлектроннаяПодписьКлиент.СоздаватьЭлектронныеПодписиНаСервере() Тогда
		Если Не ЗначениеЗаполнено(Форма.МенеджерКриптографииНаСервереОписаниеОшибки) Тогда
			ВыполнитьОбработкуОповещения(Оповещение, Истина);
			Возврат;
		КонецЕсли;
		Контекст.ОшибкаНаСервере = Форма.МенеджерКриптографииНаСервереОписаниеОшибки;
	КонецЕсли;
	
	ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
	ПараметрыСоздания.ПоказатьОшибку = Неопределено;
	
	СоздатьМенеджерКриптографии(Новый ОписаниеОповещения(
			"ПродолжитьОткрытиеНачалоПослеСозданияМенеджераКриптографии", ЭтотОбъект, Контекст),
		"ПолучениеСертификатов", ПараметрыСоздания);
	
КонецПроцедуры

// Продолжение процедуры ПродолжитьОткрытиеНачало.
Процедура ПродолжитьОткрытиеНачалоПослеСозданияМенеджераКриптографии(Результат, Контекст) Экспорт
	
	Если ТипЗнч(Результат) <> Тип("МенеджерКриптографии")
	   И Не ИспользоватьЭлектроннуюПодписьВМоделиСервиса()
	   И Не ИспользоватьСервисОблачнойПодписи() Тогда
		
		ПоказатьОшибкуОбращенияКПрограмме(
			НСтр("ru = 'Требуется программа электронной подписи и шифрования'"),
			"", Результат, Контекст.ОшибкаНаСервере);
		
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Ложь);
		Возврат;
	КонецЕсли;
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, Истина);
	
КонецПроцедуры


// Только для внутреннего использования.
Процедура ПолучитьОтпечаткиСертификатовНаКлиенте(Оповещение, ВключаяПросроченные = Ложь) Экспорт
	
	Контекст = Новый Структура;
	Контекст.Вставить("Оповещение", Оповещение);
	Контекст.Вставить("ВключаяПросроченные", ВключаяПросроченные);
	
	ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
	ПараметрыСоздания.ПоказатьОшибку = Ложь;
	
	СоздатьМенеджерКриптографии(Новый ОписаниеОповещения(
			"ПолучитьОтпечаткиСертификатовНаКлиентеПослеСозданияМенеджераКриптографии", ЭтотОбъект, Контекст),
		"ПолучениеСертификатов", ПараметрыСоздания);
	
КонецПроцедуры

// Продолжение процедуры ПолучитьОтпечаткиСертификатовНаКлиенте.
Процедура ПолучитьОтпечаткиСертификатовНаКлиентеПослеСозданияМенеджераКриптографии(МенеджерКриптографии, Контекст) Экспорт
	
	Если ТипЗнч(МенеджерКриптографии) <> Тип("МенеджерКриптографии") Тогда
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Новый Массив);
		Возврат;
	КонецЕсли;
	
	МенеджерКриптографии.НачатьПолучениеХранилищаСертификатов(
		Новый ОписаниеОповещения(
			"ПолучитьОтпечаткиСертификатовНаКлиентеПослеПолученияХранилища", ЭтотОбъект, Контекст),
		ТипХранилищаСертификатовКриптографии.ПерсональныеСертификаты);
	
КонецПроцедуры

// Продолжение процедуры ПолучитьОтпечаткиСертификатовНаКлиенте.
Процедура ПолучитьОтпечаткиСертификатовНаКлиентеПослеПолученияХранилища(ХранилищеСертификатовКриптографии, Контекст) Экспорт
	
	ХранилищеСертификатовКриптографии.НачатьПолучениеВсех(Новый ОписаниеОповещения(
		"ПолучитьОтпечаткиСертификатовНаКлиентеПослеПолученияВсех", ЭтотОбъект, Контекст));
	
КонецПроцедуры

// Продолжение процедуры ПолучитьОтпечаткиСертификатовНаКлиенте.
Процедура ПолучитьОтпечаткиСертификатовНаКлиентеПослеПолученияВсех(МассивСертификатов, Контекст) Экспорт
	
	ОтпечаткиСертификатовНаКлиенте = Новый Массив;
	
	ЭлектроннаяПодписьСлужебныйКлиентСервер.ДобавитьОтпечаткиСертификатов(ОтпечаткиСертификатовНаКлиенте,
		МассивСертификатов,
		ДобавкаВремени(),
		?(Контекст.ВключаяПросроченные, Неопределено, ОбщегоНазначенияКлиент.ДатаСеанса()));
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, ОтпечаткиСертификатовНаКлиенте);
	
КонецПроцедуры


// Только для внутреннего использования.
//
// Параметры:
//   Форма - ФормаКлиентскогоПриложения
//
Процедура ОбработатьПарольВФорме(Форма, ВнутренниеДанные, СвойстваПароля, ДополнительныеПараметры = Неопределено, НовыйПароль = Null) Экспорт
	
	Если ТипЗнч(СвойстваПароля) <> Тип("Структура") Тогда
		СвойстваПароля = Новый Структура;
		СвойстваПароля.Вставить("Значение", Неопределено);
		СвойстваПароля.Вставить("ОбработкаПоясненияПароля", Неопределено);
		// Свойство ПарольПроверен разрешает запоминание без проверки.
		// Включается когда указан НовыйПароль и при успешном выполнении операции. 
		СвойстваПароля.Вставить("ПарольПроверен", Ложь);
	КонецЕсли;
	
	Если ДополнительныеПараметры = Неопределено Тогда
		ДополнительныеПараметры = Новый Структура;
	КонецЕсли;
	
	ДополнительныеПараметры.Вставить("Сертификат", Форма.Сертификат);
	ДополнительныеПараметры.Вставить("ВводитьПарольВПрограммеЭлектроннойПодписи",
		Форма.СертификатВводитьПарольВПрограммеЭлектроннойПодписи);
	
	Если Не ДополнительныеПараметры.Свойство("ПриУстановкеПароляИзДругойОперации") Тогда
		ДополнительныеПараметры.Вставить("ПриУстановкеПароляИзДругойОперации", Ложь);
	КонецЕсли;

	Если Не ДополнительныеПараметры.Свойство("ПриИзмененииРеквизитаПароль") Тогда
		ДополнительныеПараметры.Вставить("ПриИзмененииРеквизитаПароль", Ложь);
	КонецЕсли;
	
	Если Не ДополнительныеПараметры.Свойство("ПриИзмененииРеквизитаЗапомнитьПароль") Тогда
		ДополнительныеПараметры.Вставить("ПриИзмененииРеквизитаЗапомнитьПароль", Ложь);
	КонецЕсли;
	
	Если Не ДополнительныеПараметры.Свойство("ПриУспешномВыполненииОперации") Тогда
		ДополнительныеПараметры.Вставить("ПриУспешномВыполненииОперации", Ложь);
	КонецЕсли;
	
	Если Не ДополнительныеПараметры.Свойство("ПриИзмененииСвойствСертификата") Тогда
		ДополнительныеПараметры.Вставить("ПриИзмененииСвойствСертификата", Ложь);
	КонецЕсли;
	
	ДополнительныеПараметры.Вставить("ПарольВПамяти", Ложь);
	ДополнительныеПараметры.Вставить("ПарольУстановленПрограммно", Ложь);
	ДополнительныеПараметры.Вставить("ПояснениеПароля");
	
	ОбработатьПароль(ВнутренниеДанные, Форма.Пароль, СвойстваПароля, Форма.ЗапомнитьПароль,
		ДополнительныеПараметры, НовыйПароль);
	
	Элементы = Форма.Элементы;
	
	Если Элементы.Найти("Страницы") = Неопределено
		Или Элементы.Найти("СтраницаПояснениеУсиленногоПароля") = Неопределено Тогда
		
		Возврат;
	КонецЕсли;
	
	ТекущиеСвойства = Новый Структура("ВыполнятьВМоделиСервиса", Ложь);
	ЗаполнитьЗначенияСвойств(ТекущиеСвойства, Форма);
	
	ЭлементПароль = Элементы.Пароль; // ПолеФормы
	ЭлементЗапомнитьПароль = Элементы.ЗапомнитьПароль;
	Если ТекущиеСвойства.ВыполнятьВМоделиСервиса
		И ИспользоватьЭлектроннуюПодписьВМоделиСервиса() Тогда
		
		ЭлементПароль.Доступность = Ложь;
		ЭлементЗапомнитьПароль.Доступность = Ложь;
		Элементы.Страницы.Видимость = Истина;
		Элементы.Страницы.ТекущаяСтраница = Элементы.СтраницаПояснениеУсиленногоПароля;
		Элементы.ПояснениеУсиленногоПароля.Подсказка =
			НСтр("ru = 'Сервис вышлет одноразовый пароль по SMS или E-Mail,
			           |который нужно будет ввести после получения.'");
		
	ИначеЕсли ДополнительныеПараметры.ВводитьПарольВПрограммеЭлектроннойПодписи Тогда
		
		ЭлементПароль.Доступность = Ложь;
		ЭлементЗапомнитьПароль.Доступность = Ложь;
		Элементы.Страницы.Видимость = Истина;
		Элементы.Страницы.ТекущаяСтраница = Элементы.СтраницаПояснениеУсиленногоПароля;
		Элементы.ПояснениеУсиленногоПароля.Подсказка =
			НСтр("ru = 'Для выбранного сертификата указано ""Вводить пароль в программе электронной подписи"".'");
		
	Иначе
		
		Если ДополнительныеПараметры.ПарольУстановленПрограммно Тогда
			
			Элементы.Страницы.Видимость = Истина;
			Элементы.Страницы.ТекущаяСтраница = Элементы.СтраницаПояснениеУстановленногоПароля;
			ПояснениеПароля = ДополнительныеПараметры.ПояснениеПароля;
			
			Элементы.ПояснениеУстановленногоПароля.Заголовок   = ПояснениеПароля.ТекстПояснения;
			Элементы.ПояснениеУстановленногоПароля.Гиперссылка = ПояснениеПароля.ПояснениеГиперссылка;
			
			ЭлементПояснениеУстановленногоПароляРасширеннаяПодсказка = Элементы.ПояснениеУстановленногоПароляРасширеннаяПодсказка; // ПолеФормы
			ЭлементПояснениеУстановленногоПароляРасширеннаяПодсказка.Заголовок = ПояснениеПароля.ТекстПодсказки;
			СвойстваПароля.ОбработкаПоясненияПароля = ПояснениеПароля.ОбработкаДействия;
			
			ЭлементПароль.Доступность = Истина;
			ЭлементЗапомнитьПароль.Доступность = Истина;
			
		Иначе
			
			ЭлементПароль.Доступность = Не ДополнительныеПараметры.ПарольВПамяти;
			ЭлементЗапомнитьПароль.Доступность = Не ДополнительныеПараметры.ПарольВПамяти;
			
			Если Элементы.Найти("СтраницаЗапоминаниеПароля") = Неопределено Тогда
				Элементы.Страницы.Видимость = Ложь;
			Иначе
				Элементы.Страницы.Видимость = Истина;
				Элементы.Страницы.ТекущаяСтраница = Элементы.СтраницаЗапоминаниеПароля;
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЕсли;
	
	ДополнительныеПараметры.Вставить("ПарольУказан",
		ДополнительныеПараметры.ПарольУстановленПрограммно
		Или ДополнительныеПараметры.ПарольВПамяти
		Или ДополнительныеПараметры.ПриУстановкеПароляИзДругойОперации);
	
	ЗначенияФормы = ПолучитьДанныеОблачнойПодписи(Форма, "ДанныеСертификата");
	Если ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ДополнительныеПараметры, "ПриОткрытии", Ложь) 
		И ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ЗначенияФормы, "Облачный", Ложь) Тогда
		УбратьПароль = ДополнительныеПараметры.ПарольВПамяти;
		Элементы.Страницы.Видимость = НЕ УбратьПароль;
		ЭлементПароль.Видимость = НЕ УбратьПароль;
	КонецЕсли;	
	
КонецПроцедуры

// Только для внутреннего использования.
Процедура ПояснениеУстановленногоПароляНажатие(Форма, Элемент, СвойстваПароля) Экспорт
	
	Если ТипЗнч(СвойстваПароля.ОбработкаПоясненияПароля) = Тип("ОписаниеОповещения") Тогда
		Результат = Новый Структура;
		Результат.Вставить("Сертификат", Форма.Сертификат);
		Результат.Вставить("Действие", "ПояснениеНажатие");
		ВыполнитьОбработкуОповещения(СвойстваПароля.ОбработкаПоясненияПароля, Результат);
	КонецЕсли;
	
КонецПроцедуры

// Только для внутреннего использования.
Процедура ПояснениеУстановленногоПароляОбработкаНавигационнойСсылки(Форма, Элемент, НавигационнаяСсылка,
			СтандартнаяОбработка, СвойстваПароля) Экспорт
	
	СтандартнаяОбработка = Ложь;
	
	Если ТипЗнч(СвойстваПароля.ОбработкаПоясненияПароля) = Тип("ОписаниеОповещения") Тогда
		Результат = Новый Структура;
		Результат.Вставить("Сертификат", Форма.Сертификат);
		Результат.Вставить("Действие", НавигационнаяСсылка);
		ВыполнитьОбработкуОповещения(СвойстваПароля.ОбработкаПоясненияПароля, Результат);
	КонецЕсли;
	
КонецПроцедуры

// Только для внутреннего использования.
Процедура ПредставлениеДанныхНажатие(Форма, Элемент, СтандартнаяОбработка, ТекущийСписокПредставлений) Экспорт
	
	СтандартнаяОбработка = Ложь;
	
	Если ТекущийСписокПредставлений.Количество() > 1 Тогда
		СписокПредставленийДанных = Новый Массив;
		Для Каждого ЭлементСписка Из ТекущийСписокПредставлений Цикл
			СписокПредставленийДанных.Добавить(ЭлементСписка.Представление);
		КонецЦикла;
		ПараметрыФормы = Новый Структура;
		ПараметрыФормы.Вставить("СписокПредставленийДанных", СписокПредставленийДанных);
		ПараметрыФормы.Вставить("ПредставлениеДанных", Форма.ПредставлениеДанных);
		НоваяФорма = ОткрытьФорму("Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования.Форма.ПросмотрДанных",
			ПараметрыФормы, Элемент);
		Если НоваяФорма = Неопределено Тогда
			Возврат;
		КонецЕсли;
		НоваяФорма.УстановитьСписокПредставлений(ТекущийСписокПредставлений, Неопределено);
	Иначе
		Значение = ТекущийСписокПредставлений[0].Значение;
		Если ТипЗнч(Значение) = Тип("ОписаниеОповещения") Тогда
			ВыполнитьОбработкуОповещения(Значение);
		Иначе
			ПоказатьЗначение(, Значение);
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// Только для внутреннего использования.
//
// Параметры:
//   Форма - ФормаКлиентскогоПриложения
//
Функция ПолноеПредставлениеДанных(Форма) Экспорт
	
	Элементы = Форма.Элементы;
	ЭлементПредставлениеДанных = Элементы.ПредставлениеДанных; // ПолеФормы
	Если Элементы.ПредставлениеДанных.ПоложениеЗаголовка <> ПоложениеЗаголовкаЭлементаФормы.Нет
	   И ЗначениеЗаполнено(ЭлементПредставлениеДанных.Заголовок) Тогда
	
		Возврат ЭлементПредставлениеДанных.Заголовок + ": " + Форма.ПредставлениеДанных;
	Иначе
		Возврат Форма.ПредставлениеДанных;
	КонецЕсли;
	
КонецФункции

// Только для внутреннего использования.
Процедура СертификатПодборИзСпискаВыбора(Форма, Текст, ДанныеВыбора, СтандартнаяОбработка) Экспорт
	
	Если Текст = "" И Форма.СертификатСписокВыбора.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	СтандартнаяОбработка = Ложь;
	ДанныеВыбора = Новый СписокЗначений;
	
	Для каждого ЭлементСписка Из Форма.СертификатСписокВыбора Цикл
		Если СтрНайти(ВРег(ЭлементСписка.Представление), ВРег(Текст)) > 0 Тогда
			ДанныеВыбора.Добавить(ЭлементСписка.Значение, ЭлементСписка.Представление);
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

// Только для внутреннего использования.
Асинх Процедура ВыполнитьНаСтороне(Оповещение, Операция, СторонаВыполнения, ПараметрыВыполнения) Экспорт
	
	Контекст = ВыполнитьНаСторонеНовыйКонтекст();
	
	ЗаполнитьЗначенияСвойств(Контекст, ПараметрыВыполнения);
	
	СвойстваОблачнойПодписи = ПолучитьСвойстваОблачнойПодписи(Контекст.ОписаниеДанных);
	ИспользоватьОблачнуюПодпись = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыВыполнения, "ИспользоватьОблачнуюПодпись", Истина);
	
	Контекст.Вставить("Оповещение",       Оповещение);
	Контекст.Вставить("Операция",         Операция); // Подписание, Шифрование, Расшифровка.
	Контекст.Вставить("НаСторонеКлиента", СторонаВыполнения = "НаСторонеКлиента");
	Контекст.Вставить("ОперацияНачалась", Ложь);
	Контекст.Вставить("ИспользоватьОблачнуюПодпись", ИспользоватьОблачнуюПодпись);
	
	Если Контекст.НаСторонеКлиента Тогда
		Если ЗначениеЗаполнено(СвойстваОблачнойПодписи.УчетнаяЗапись) Тогда
			Контекст.Вставить("МенеджерКриптографии", "ОблачнаяПодпись");
			ВыполнитьНаСторонеОблачнойПодписи(Контекст);
		ИначеЕсли Контекст.Операция = "Шифрование" И ИспользоватьЭлектроннуюПодписьВМоделиСервиса() Тогда
			Контекст.Вставить("МенеджерКриптографии", "СервисКриптографии");
			ВыполнитьНаСторонеВМоделиСервиса(Null, Контекст);
		ИначеЕсли (Контекст.Операция = "Расшифровка" Или Контекст.Операция = "Подписание")
			И ИспользоватьЭлектроннуюПодписьВМоделиСервиса()
			И Контекст.Форма.ВыполнятьВМоделиСервиса Тогда
				Контекст.Вставить("МенеджерКриптографии", "СервисКриптографии");
				ВыполнитьНаСторонеВМоделиСервиса(Null, Контекст);
		Иначе
			
			Если ЗначениеЗаполнено(Контекст.Форма.СертификатПрограмма) Тогда
				Программа = Контекст.Форма.СертификатПрограмма;
			Иначе
				Если Операция = "Подписание" Или Операция = "Расшифровка" Тогда
					ТребуетсяЗакрытыйКлюч = Истина;
				Иначе
					ТребуетсяЗакрытыйКлюч = Неопределено;
				КонецЕсли;
				ПрограммаПоСертификатуРезультат = Ждать ПрограммаПоСертификату(
					ПараметрыВыполнения.СертификатАдрес, ТребуетсяЗакрытыйКлюч, Неопределено, Истина);
				Если ЗначениеЗаполнено(ПрограммаПоСертификатуРезультат.Программа) Тогда
					Программа = ПрограммаПоСертификатуРезультат.Программа;
				Иначе
					ОшибкаНаКлиенте = Новый Структура("ОписаниеОшибки", ПрограммаПоСертификатуРезультат.Ошибка);
					ОшибкаНаКлиенте.Вставить("Инструкция", Истина);
					ВыполнитьНаСторонеПослеЦикла(ОшибкаНаКлиенте, Контекст);
					Возврат;
				КонецЕсли;
			КонецЕсли;
			
			ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
			ПараметрыСоздания.ПоказатьОшибку = Неопределено;
			ПараметрыСоздания.Программа = Программа;
			ПараметрыСоздания.ИнтерактивныйРежим = Контекст.Форма.СертификатВводитьПарольВПрограммеЭлектроннойПодписи;
			
			СоздатьМенеджерКриптографии(Новый ОписаниеОповещения(
					"ВыполнитьНаСторонеПослеСозданияМенеджераКриптографии", ЭтотОбъект, Контекст),
				Операция, ПараметрыСоздания);
				
		КонецЕсли;
	Иначе
		ВыполнитьНаСторонеЦиклЗапуск(Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
Процедура ВыполнитьНаСторонеПослеСозданияМенеджераКриптографии(Результат, Контекст) Экспорт
	
	Если ТипЗнч(Результат) <> Тип("МенеджерКриптографии") Тогда
		Если Контекст.Операция = "Шифрование" 
			И ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Контекст, "ИспользоватьОблачнуюПодпись", Истина) = Истина 
			И ШифроватьДанныеОблачнойПодписью() Тогда
			Контекст.Вставить("МенеджерКриптографии", "ОблачнаяПодпись");
			ВыполнитьНаСторонеОблачнойПодписи(Контекст);
		Иначе	
			ВыполнитьОбработкуОповещения(Контекст.Оповещение, Новый Структура("Ошибка", Результат));
			Возврат;
		КонецЕсли;
	КонецЕсли;
	Контекст.Вставить("МенеджерКриптографии", Результат);
	
	// Если личный сертификат шифрования не используется, тогда его не нужно искать.
	Если Контекст.Операция <> "Шифрование"
	 Или ЗначениеЗаполнено(Контекст.Форма.СертификатОтпечаток) Тогда
		
		ПолучитьСертификатПоОтпечатку(Новый ОписаниеОповещения(
				"ВыполнитьНаСторонеПослеПоискаСертификата", ЭтотОбъект, Контекст),
			Контекст.Форма.СертификатОтпечаток, Истина, Неопределено,
			?(ТипЗнч(Результат) <> Тип("МенеджерКриптографии"), Контекст.Форма.СертификатПрограмма, Результат));

	Иначе
		ВыполнитьНаСторонеПослеПоискаСертификата(Null, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
//
// Параметры:
//   Контекст - Структура:
//     * СертификатКриптографии - СертификатКриптографии
//
Процедура ВыполнитьНаСторонеПослеПоискаСертификата(Результат, Контекст) Экспорт
	
	Если ТипЗнч(Результат) <> Тип("СертификатКриптографии") И Результат <> Null Тогда
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Новый Структура("Ошибка", Результат));
		Возврат;
	КонецЕсли;
	Контекст.Вставить("СертификатКриптографии", Результат);
	
	Если Контекст.Операция = "Подписание" Тогда
		Если Не ИспользуетсяИнтерактивныйРежимКриптографии(Контекст.МенеджерКриптографии) Тогда
			Контекст.МенеджерКриптографии.ПарольДоступаКЗакрытомуКлючу = Контекст.ЗначениеПароля;
		КонецЕсли;
		Контекст.Удалить("ЗначениеПароля");
		Контекст.СертификатКриптографии.НачатьВыгрузку(Новый ОписаниеОповещения(
			"ВыполнитьНаСторонеПослеВыгрузкиСертификата", ЭтотОбъект, Контекст));
		
	ИначеЕсли Контекст.Операция = "Шифрование" Тогда
		СвойстваСертификатов = Контекст.ОписаниеДанных.СертификатыШифрования;
		Если ТипЗнч(СвойстваСертификатов) = Тип("Строка") Тогда
			СвойстваСертификатов = ПолучитьИзВременногоХранилища(СвойстваСертификатов);
		КонецЕсли;
		Контекст.Вставить("Индекс", -1);
		Контекст.Вставить("СвойстваСертификатов", СвойстваСертификатов);
		Контекст.Вставить("СертификатыШифрования", Новый Массив);
		ВыполнитьНаСторонеПодготовкаСертификатовЦиклНачало(Контекст);
		Возврат;
	Иначе
		Если Не ИспользуетсяИнтерактивныйРежимКриптографии(Контекст.МенеджерКриптографии) Тогда
			Контекст.МенеджерКриптографии.ПарольДоступаКЗакрытомуКлючу = Контекст.ЗначениеПароля;
		КонецЕсли;
		Контекст.Удалить("ЗначениеПароля");
		ВыполнитьНаСторонеЦиклЗапуск(Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
//
// Параметры:
//   Контекст - Структура
//
Процедура ВыполнитьНаСторонеПодготовкаСертификатовЦиклНачало(Контекст)
	
	Если Контекст.СвойстваСертификатов.Количество() <= Контекст.Индекс + 1 Тогда
		ВыполнитьНаСторонеЦиклЗапуск(Контекст);
		Возврат;
	КонецЕсли;
	Контекст.Индекс = Контекст.Индекс + 1;
	
	СертификатКриптографии = Новый СертификатКриптографии;
	СертификатКриптографии.НачатьИнициализацию(Новый ОписаниеОповещения(
			"ВыполнитьНаСторонеПодготовкаСертификатовПослеИнициализацииСертификата", ЭтотОбъект, Контекст),
		Контекст.СвойстваСертификатов[Контекст.Индекс].Сертификат);
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
//
// Параметры:
//   Контекст - Структура:
//     * СертификатыШифрования - Массив
//
Процедура ВыполнитьНаСторонеПодготовкаСертификатовПослеИнициализацииСертификата(СертификатКриптографии, Контекст) Экспорт
	
	Контекст.СертификатыШифрования.Добавить(СертификатКриптографии);
	
	ВыполнитьНаСторонеПодготовкаСертификатовЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
Асинх Процедура ВыполнитьНаСторонеПослеВыгрузкиСертификата(ВыгруженныеДанные, Контекст) Экспорт
	
	Контекст.Вставить("СвойстваСертификата", Ждать СвойстваСертификата(
		Контекст.СертификатКриптографии));
	Контекст.СвойстваСертификата.Вставить("ДвоичныеДанные", ВыгруженныеДанные);
	
	ВыполнитьНаСторонеЦиклЗапуск(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
Процедура ВыполнитьНаСторонеЦиклЗапуск(Контекст)
	
	Если Контекст.ОписаниеДанных.Свойство("Данные") Тогда
		ЭлементыДанных = Новый Массив;
		ЭлементыДанных.Добавить(Контекст.ОписаниеДанных);
	Иначе
		ЭлементыДанных = Контекст.ОписаниеДанных.НаборДанных;
	КонецЕсли;
	
	Контекст.Вставить("ЭлементыДанных", ЭлементыДанных);
	Контекст.Вставить("Индекс", -1);
	
	ВыполнитьНаСторонеЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
Процедура ВыполнитьНаСторонеЦиклНачало(Контекст)
	
	Если Контекст.ЭлементыДанных.Количество() <= Контекст.Индекс + 1 Тогда
		ВыполнитьНаСторонеПослеЦикла(Неопределено, Контекст);
		Возврат;
	КонецЕсли;
	
	Оповещение = Новый ОписаниеОповещения(
		"ВыполнитьНаСторонеЦиклНачалоПродолжение", ЭтотОбъект, Контекст);
	
	СтандартныеПодсистемыКлиент.НачатьВыполнениеОбработкиОповещения(Оповещение);
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
//
// Параметры:
//  Результат - Число
//  Контекст - см. ВыполнитьНаСторонеНовыйКонтекст
//
Процедура ВыполнитьНаСторонеЦиклНачалоПродолжение(Результат, Контекст) Экспорт
	
	Контекст.Индекс = Контекст.Индекс + 1;
	Контекст.Вставить("ЭлементДанных", Контекст.ЭлементыДанных[Контекст.Индекс]);
	
	Если Не Контекст.ОписаниеДанных.Свойство("Данные") Тогда
		Контекст.ОписаниеДанных.Вставить("ТекущийЭлементНабораДанных", Контекст.ЭлементДанных);
	КонецЕсли;
	
	Если Контекст.Операция = "Подписание"
	   И Контекст.ЭлементДанных.Свойство("СвойстваПодписи")
	 Или Контекст.Операция = "Шифрование"
	   И Контекст.ЭлементДанных.Свойство("ЗашифрованныеДанные")
	 Или Контекст.Операция = "Расшифровка"
	   И Контекст.ЭлементДанных.Свойство("РасшифрованныеДанные") Тогда
		
		ВыполнитьНаСторонеЦиклНачало(Контекст);
		Возврат;
	КонецЕсли;
	
	ПолучитьДанныеИзОписанияДанных(Новый ОписаниеОповещения(
			"ВыполнитьНаСторонеЦиклПослеПолученияДанных", ЭтотОбъект, Контекст),
		Контекст.Форма, Контекст.ОписаниеДанных, Контекст.ЭлементДанных.Данные, Контекст.НаСторонеКлиента);
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
Процедура ВыполнитьНаСторонеЦиклПослеОперацииНаКлиентеXMLDSig(КонвертXML, Контекст) Экспорт
	
	Контекст.ОперацияНачалась = Истина;
	
	СвойстваПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.СвойстваПодписи(КонвертXML,
		Контекст.СвойстваСертификата,
		Контекст.Форма.Комментарий,
		ПользователиКлиент.АвторизованныйПользователь());
	
	Если Контекст.СертификатВерен <> Неопределено Тогда
		СвойстваПодписи.ДатаПодписи = ОбщегоНазначенияКлиент.ДатаСеанса();
		СвойстваПодписи.ДатаПроверкиПодписи = СвойстваПодписи.ДатаПодписи;
		СвойстваПодписи.ПодписьВерна = Контекст.СертификатВерен;
	КонецЕсли;
	
	СвойстваПодписи.ТребуетсяПроверка = Контекст.ТребуетсяПроверка;
	
	ВыполнитьНаСторонеЦиклПослеПодписания(СвойстваПодписи, Контекст);
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
Процедура ВыполнитьНаСторонеЦиклПослеОшибкиОперацииНаКлиентеXMLDSig(ТекстОшибки, Контекст) Экспорт
	
	ОшибкаНаКлиенте = Новый Структура("ОписаниеОшибки", ТекстОшибки);
	ОшибкаНаКлиенте.Вставить("Инструкция", Истина);
	
	ВыполнитьНаСторонеПослеЦикла(ОшибкаНаКлиенте, Контекст);
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
//
// Параметры:
//  Результат - ДвоичныеДанные
//            - Строка
//            - Структура
//  Контекст - см. ВыполнитьНаСторонеНовыйКонтекст
//
Процедура ВыполнитьНаСторонеЦиклПослеПолученияДанных(Результат, Контекст) Экспорт
	
	ТипРезультата = ТипЗнч(Результат);
	
	Если ТипРезультата <> Тип("Строка")
		И ТипРезультата <> Тип("ДвоичныеДанные")
		И ТипРезультата <> Тип("Структура") Тогда
			
		Ошибка = Новый Структура("ОписаниеОшибки",
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ЗаголовокОшибкиПолученияДанных(Контекст.Операция)
			+ Символы.ПС
			+ НСтр("ru = 'Некорректный тип данных: %1'"));
		ВыполнитьНаСторонеПослеЦикла(Ошибка, Контекст);
		Возврат;
	КонецЕсли;
	
	ЭтоXMLDSig = (ТипРезультата = Тип("Структура") И Результат.Свойство("ПараметрыXMLDSig"));
	ЭтоCMS     = (ТипРезультата = Тип("Структура") И Результат.Свойство("ПараметрыCMS"));
	
	Если ЭтоXMLDSig И Не Результат.Свойство("КонвертXML") Тогда
		Результат = Новый Структура(Новый ФиксированнаяСтруктура(Результат));
		Результат.Вставить("КонвертXML", Результат.КонвертSOAP);
	КонецЕсли;
	
	Если ТипРезультата = Тип("Структура")
	   И Не ЭтоXMLDSig
	   И Не ЭтоCMS Тогда
		
		Ошибка = Новый Структура("ОписаниеОшибки",
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ЗаголовокОшибкиПолученияДанных(Контекст.Операция)
			+ Символы.ПС + Результат.ОписаниеОшибки);
		ВыполнитьНаСторонеПослеЦикла(Ошибка, Контекст);
		Возврат;
	КонецЕсли;
	
	Данные = Результат;
	
	Если Контекст.НаСторонеКлиента Тогда
		МенеджерКриптографии = Контекст.МенеджерКриптографии;
		
		ПараметрыОперации = Новый Структура;
		ПараметрыОперации.Вставить("Операция", Контекст.ОписаниеДанных.Операция);
		ПараметрыОперации.Вставить("ЗаголовокДанных", Контекст.ОписаниеДанных.ЗаголовокДанных);
		
		Если ЭтоXMLDSig Тогда
			
			Если Контекст.Операция <> "Подписание" Тогда
				Ошибка = Новый Структура("ОписаниеОшибки",
					СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Внешняя компонента %1 может использоваться только для подписания.'"), "ExtraCryptoAPI"));
				ВыполнитьНаСторонеПослеЦикла(Ошибка, Контекст);
				Возврат;
			КонецЕсли;
			
			ОповещениеУспех = Новый ОписаниеОповещения(
				"ВыполнитьНаСторонеЦиклПослеОперацииНаКлиентеXMLDSig", ЭтотОбъект, Контекст);
			
			ОповещениеОшибка = Новый ОписаниеОповещения(
				"ВыполнитьНаСторонеЦиклПослеОшибкиОперацииНаКлиентеXMLDSig", ЭтотОбъект, Контекст);
			
			Оповещения = Новый Структура;
			Оповещения.Вставить("Успех", ОповещениеУспех);
			Оповещения.Вставить("Ошибка", ОповещениеОшибка);
			
			НачатьВыгрузкуСертификатаКриптографииДляПодписанияXMLDSig(Оповещения,
				Результат.КонвертXML,
				Результат.ПараметрыXMLDSig,
				Контекст.СертификатКриптографии,
				Контекст.МенеджерКриптографии);
		
		ИначеЕсли ЭтоCMS Тогда
			Если Контекст.Операция <> "Подписание" Тогда
				Ошибка = Новый Структура("ОписаниеОшибки",
					СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Внешняя компонента %1 может использоваться только для подписания.'"), "ExtraCryptoAPI"));
				ВыполнитьНаСторонеПослеЦикла(Ошибка, Контекст);
				Возврат;
			КонецЕсли;
			
			Если МенеджерКриптографии = "СервисКриптографии" Тогда
				Если Результат.ПараметрыCMS.ВключениеСертификатовВПодпись <> РежимВключенияСертификатовКриптографии.ВключатьСертификатСубъекта Тогда
					Ошибка = Новый Структура("ОписаниеОшибки",
						НСтр("ru = 'Подписание сертификатом с программой встроенного криптопровайдера недоступно.
						           |Выберите другой сертификат из установленных на компьютере.'"));
					ВыполнитьНаСторонеПослеЦикла(Ошибка, Контекст);
					Возврат;
				КонецЕсли;
				Если ТипЗнч(Данные.Данные) = Тип("ДвоичныеДанные") Тогда
					ДанныеДляПодписания = Данные.Данные;
				Иначе
					ДанныеДляПодписания = ПолучитьДвоичныеДанныеИзСтроки(Данные.Данные);
				КонецЕсли;
				ПараметрыОперации.Вставить("ОтсоединеннаяПодпись", Результат.ПараметрыCMS.Открепленная);
				Оповещение = Новый ОписаниеОповещения(
					"ВыполнитьНаСторонеЦиклПослеОперацииНаКлиенте", ЭтотОбъект, Контекст,
					"ВыполнитьНаСторонеЦиклПослеОшибкиОперацииНаКлиенте", ЭтотОбъект);
				СертификатДляПодписи = ПолучитьИзВременногоХранилища(Контекст.ОписаниеДанных.ВыбранныйСертификат.Данные);
				МодульСервисКриптографииКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииКлиент");
				МодульСервисКриптографииКлиент.Подписать(Оповещение, ДанныеДляПодписания, СертификатДляПодписи, , ПараметрыОперации);
			Иначе
				ОповещениеУспех = Новый ОписаниеОповещения(
					"ВыполнитьНаСторонеЦиклПослеОперацииНаКлиентеXMLDSig", ЭтотОбъект, Контекст);
				
				ОповещениеОшибка = Новый ОписаниеОповещения(
					"ВыполнитьНаСторонеЦиклПослеОшибкиОперацииНаКлиентеXMLDSig", ЭтотОбъект, Контекст);
				
				Оповещения = Новый Структура;
				Оповещения.Вставить("Успех", ОповещениеУспех);
				Оповещения.Вставить("Ошибка", ОповещениеОшибка);
				
				НачатьВыгрузкуСертификатаКриптографииДляПодписанияCMS(Оповещения,
					Результат.Данные,
					Результат.ПараметрыCMS,
					Контекст.СертификатКриптографии,
					Контекст.МенеджерКриптографии);
			КонецЕсли;
		Иначе
			Оповещение = Новый ОписаниеОповещения(
				"ВыполнитьНаСторонеЦиклПослеОперацииНаКлиенте", ЭтотОбъект, Контекст,
				"ВыполнитьНаСторонеЦиклПослеОшибкиОперацииНаКлиенте", ЭтотОбъект);
			
			Если МенеджерКриптографии = "ОблачнаяПодпись" Тогда
				ВыполнитьОперациюОблачнойПодписи(Оповещение, Контекст, Данные, ПараметрыОперации);
			
			ИначеЕсли Контекст.Операция = "Подписание" Тогда
				
				Если МенеджерКриптографии = "СервисКриптографии" Тогда
					СертификатДляПодписи = ПолучитьИзВременногоХранилища(Контекст.ОписаниеДанных.ВыбранныйСертификат.Данные);
					МодульСервисКриптографииКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииКлиент");
					МодульСервисКриптографииКлиент.Подписать(Оповещение, Данные, СертификатДляПодписи, , ПараметрыОперации);
				Иначе
					Если ЭлектроннаяПодписьКлиент.ОбщиеНастройки().ДоступнаУсовершенствованнаяПодпись Тогда
						Попытка
							НастройкиПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.НастройкиСозданияПодписи(
								Контекст.ОписаниеДанных.ТипПодписи,
								ЭлектроннаяПодписьКлиент.ОбщиеНастройки().АдресаСерверовМетокВремени);
						Исключение
							ВыполнитьНаСторонеЦиклПослеОшибкиОперацииНаКлиенте(ИнформацияОбОшибке(), Ложь, Контекст);
							Возврат;
						КонецПопытки;
						Если ЗначениеЗаполнено(НастройкиПодписи.АдресаСерверовМетокВремени) Тогда
							МенеджерКриптографии.АдресаСерверовМетокВремени = НастройкиПодписи.АдресаСерверовМетокВремени;
						КонецЕсли;
						МенеджерКриптографии.НачатьПодписывание(Оповещение, Данные, Контекст.СертификатКриптографии, 
							НастройкиПодписи.ТипПодписи);
					Иначе
						МенеджерКриптографии.НачатьПодписывание(Оповещение, Данные, Контекст.СертификатКриптографии);
					КонецЕсли;
				КонецЕсли;
				
			ИначеЕсли Контекст.Операция = "Шифрование" Тогда
				
				Если МенеджерКриптографии = "СервисКриптографии" Тогда
					МодульСервисКриптографииКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииКлиент");
					МодульСервисКриптографииКлиент.Зашифровать(Оповещение, Данные, Контекст.СертификатыШифрования, , ПараметрыОперации);
				Иначе
					МенеджерКриптографии.НачатьШифрование(Оповещение, Данные, Контекст.СертификатыШифрования);
				КонецЕсли;
				
			Иначе
				
				Если МенеджерКриптографии = "СервисКриптографии" Тогда
					МодульСервисКриптографииКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииКлиент");
					МодульСервисКриптографииКлиент.Расшифровать(Оповещение, Данные, , ПараметрыОперации);
				Иначе
					МенеджерКриптографии.НачатьРасшифровку(Оповещение, Данные);
				КонецЕсли;
				
			КонецЕсли;
			
		КонецЕсли;
		
		Возврат;
		
	КонецЕсли;
	
	ЭлементДанныхДляСервера = Новый Структура;
	ЭлементДанныхДляСервера.Вставить("Данные", Данные);
	
	ПараметрыДляСервера = Новый Структура;
	ПараметрыДляСервера.Вставить("Операция", Контекст.Операция);
	ПараметрыДляСервера.Вставить("ИдентификаторФормы",  Контекст.ИдентификаторФормы);
	ПараметрыДляСервера.Вставить("СертификатВерен",     Контекст.СертификатВерен);
	ПараметрыДляСервера.Вставить("ТребуетсяПроверка",   Контекст.ТребуетсяПроверка);
	ПараметрыДляСервера.Вставить("СертификатПрограмма", Контекст.Форма.СертификатПрограмма);
	ПараметрыДляСервера.Вставить("СертификатОтпечаток", Контекст.Форма.СертификатОтпечаток);
	ПараметрыДляСервера.Вставить("ЭлементДанныхДляСервера", ЭлементДанныхДляСервера);
	
	ОшибкаНаСервере = Новый Структура;
	АдресРезультата = Неопределено;
	
	Если Не ЗначениеЗаполнено(ПараметрыДляСервера.СертификатПрограмма) Тогда
		ПараметрыДляСервера.Вставить("ДанныеДляСозданияМенеджераКриптографии", Контекст.СертификатАдрес);
	КонецЕсли;
	
	Если Контекст.Операция = "Подписание" Тогда
	
		ПараметрыДляСервера.Вставить("ТипПодписи",     Контекст.ОписаниеДанных.ТипПодписи);
		ПараметрыДляСервера.Вставить("Комментарий",    Контекст.Форма.Комментарий);
		ПараметрыДляСервера.Вставить("ЗначениеПароля", Контекст.ЗначениеПароля);
		ПараметрыДляСервера.Вставить("ВыбраннаяДоверенность", Контекст.ОписаниеДанных.ВыбраннаяДоверенность);
		ПараметрыДляСервера.Вставить("РезультатПроверкиМЧДДляПодписания", Контекст.ОписаниеДанных.РезультатПроверкиМЧДДляПодписания);
		
		Если Контекст.ЭлементДанных.Свойство("Объект")
		   И Не ТипЗнч(Контекст.ЭлементДанных.Объект) = Тип("ОписаниеОповещения") Тогда
			
			ЭлементДанныхДляСервера.Вставить("Объект", Контекст.ЭлементДанных.Объект);
			
			Если Контекст.ЭлементДанных.Свойство("ВерсияОбъекта") Тогда
				ЭлементДанныхДляСервера.Свойство("ВерсияОбъекта", Контекст.ЭлементДанных.ВерсияОбъекта);
			КонецЕсли;
		КонецЕсли;
		
	ИначеЕсли Контекст.Операция = "Шифрование" Тогда
	
		ПараметрыДляСервера.Вставить("АдресСертификатов", Контекст.ОписаниеДанных.СертификатыШифрования);
		
	Иначе // Расшифровка.
		ПараметрыДляСервера.Вставить("ЗначениеПароля", Контекст.ЗначениеПароля);
	КонецЕсли;
	
	Успех = ЭлектроннаяПодписьСлужебныйВызовСервера.ВыполнитьНаСторонеСервера(ПараметрыДляСервера,
		АдресРезультата, Контекст.ОперацияНачалась, ОшибкаНаСервере);
	
	Если Не Успех Тогда
		ВыполнитьНаСторонеПослеЦикла(ОшибкаНаСервере, Контекст);
		
	ИначеЕсли Контекст.Операция = "Подписание" Тогда
		ВыполнитьНаСторонеЦиклПослеПодписания(АдресРезультата, Контекст);
		
	ИначеЕсли Контекст.Операция = "Шифрование" Тогда
		ВыполнитьНаСторонеЦиклПослеШифрования(АдресРезультата, Контекст);
	Иначе // Расшифровка.
		ВыполнитьНаСторонеЦиклПослеРасшифровки(АдресРезультата, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
Процедура ВыполнитьНаСторонеЦиклПослеОшибкиОперацииНаКлиенте(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
	
	СтандартнаяОбработка = Ложь;
	
	ОшибкаНаКлиенте = Новый Структура("ОписаниеОшибки", ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
	ОшибкаНаКлиенте.Вставить("Инструкция", Истина);
	
	ВыполнитьНаСторонеПослеЦикла(ОшибкаНаКлиенте, Контекст);
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
// 
// Параметры:
//   ДвоичныеДанные - Структура:
//   * ИнформацияОбОшибке - Структура:
//   ** Описание - Строка
//   Контекст - Структура
//
Асинх Процедура ВыполнитьНаСторонеЦиклПослеОперацииНаКлиенте(ДвоичныеДанные, Контекст) Экспорт
	
	Если Контекст.Свойство("МенеджерКриптографии") И Контекст.МенеджерКриптографии = "СервисКриптографии" Тогда
		
		Если Не ДвоичныеДанные.Выполнено Тогда
			ОшибкаНаКлиенте = Новый Структура("ОписаниеОшибки", ДвоичныеДанные.ИнформацияОбОшибке.Описание);
			ВыполнитьНаСторонеПослеЦикла(ОшибкаНаКлиенте, Контекст);
			Возврат;
		КонецЕсли;
		
		Если Контекст.Операция = "Подписание" Тогда
			ДвоичныеДанные = ДвоичныеДанные.Подпись;
		ИначеЕсли Контекст.Операция = "Шифрование" Тогда
			ДвоичныеДанные = ДвоичныеДанные.ЗашифрованныеДанные;
		Иначе
			ДвоичныеДанные = ДвоичныеДанные.РасшифрованныеДанные;
		КонецЕсли;
		
	ИначеЕсли Контекст.Свойство("МенеджерКриптографии") И Контекст.МенеджерКриптографии = "ОблачнаяПодпись" Тогда
		
		Если Не ДвоичныеДанные.Выполнено Тогда
			Если ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Контекст, "ИспользоватьОблачнуюПодпись", Ложь) Тогда
				Контекст.Вставить("ИспользоватьОблачнуюПодпись", Ложь);
				ВыполнитьНаСтороне(Контекст.Оповещение, Контекст.Операция, "НаСторонеКлиента", Контекст);
			Иначе
				ОшибкаНаКлиенте = Новый Структура("ОписаниеОшибки",
					ТекстОшибкиОблачнаяПодпись(Контекст.Операция, ДвоичныеДанные));
				ВыполнитьНаСторонеПослеЦикла(ОшибкаНаКлиенте, Контекст);
			КонецЕсли;
			Возврат;
		КонецЕсли;
		
		ДвоичныеДанные = ДвоичныеДанные.Результат;
		
	КонецЕсли;
	
	ОписаниеОшибки = "";
	Если Контекст.Операция = "Подписание"
	   И ЭлектроннаяПодписьСлужебныйКлиентСервер.ПустыеДанныеПодписи(ДвоичныеДанные, ОписаниеОшибки)
	 Или Контекст.Операция = "Шифрование"
	   И ЭлектроннаяПодписьСлужебныйКлиентСервер.ПустыеЗашифрованныеДанные(ДвоичныеДанные, ОписаниеОшибки) Тогда

		ОшибкаНаКлиенте = Новый Структура("ОписаниеОшибки", ОписаниеОшибки);
		ВыполнитьНаСторонеПослеЦикла(ОшибкаНаКлиенте, Контекст);
		Возврат;
	КонецЕсли;
	
	Контекст.ОперацияНачалась = Истина;
	
	Если Контекст.Операция = "Подписание" Тогда
		Если ТипЗнч(ДвоичныеДанные) = Тип("Массив") Тогда
			ВыполнитьНаСторонеЦиклПослеПодписанияПакета(ДвоичныеДанные, Контекст);
		Иначе
			Если Контекст.Свойство("МенеджерКриптографии") И ТипЗнч(Контекст.МенеджерКриптографии) = Тип(
				"МенеджерКриптографии") И ЭлектроннаяПодписьКлиент.ОбщиеНастройки().ДоступнаУсовершенствованнаяПодпись Тогда

				СвойстваПодписи = Ждать СвойстваПодписиЧтениеМенеджеромКриптографии(ДвоичныеДанные, Контекст.МенеджерКриптографии, Ложь);
			Иначе
				СвойстваПодписи = Ждать СвойстваПодписиИзДвоичныхДанных(ДвоичныеДанные, Ложь);
			КонецЕсли;
			
			Если СвойстваПодписи.Успех = Ложь Тогда
				ДанныеПодписи = Base64Строка(ДвоичныеДанные);
				ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru='%1.
						 |Результат подписи: %2'"), СвойстваПодписи.ТекстОшибки, ДанныеПодписи);
				ОшибкаНаКлиенте = Новый Структура("ОписаниеОшибки", ОписаниеОшибки);
				ОшибкаНаКлиенте.Вставить("Инструкция", Истина);
				ВыполнитьНаСторонеПослеЦикла(ОшибкаНаКлиенте, Контекст);
				Возврат;
			КонецЕсли;

			СвойстваПодписи = ПолучитьСвойстваПодписиПослеПодписания(ДвоичныеДанные, Контекст, СвойстваПодписи);
			ВыполнитьНаСторонеЦиклПослеПодписания(СвойстваПодписи, Контекст);
		КонецЕсли;
	ИначеЕсли Контекст.Операция = "Шифрование" Тогда
		ВыполнитьНаСторонеЦиклПослеШифрования(ДвоичныеДанные, Контекст);
	Иначе
		ВыполнитьНаСторонеЦиклПослеРасшифровки(ДвоичныеДанные, Контекст);
	КонецЕсли;
	
КонецПроцедуры 

Функция ПолучитьСвойстваПодписиПослеПодписания(ДвоичныеДанные, Контекст, ПараметрыПодписи = Неопределено)
	
	СвойстваПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.СвойстваПодписи(ДвоичныеДанные,
		Контекст.СвойстваСертификата,
		Контекст.Форма.Комментарий,
		ПользователиКлиент.АвторизованныйПользователь(),, ПараметрыПодписи);
		
	СвойстваПодписи.ДатаПодписи = ?(ЗначениеЗаполнено(СвойстваПодписи.НеподтвержденнаяДатаПодписи),
		СвойстваПодписи.НеподтвержденнаяДатаПодписи, ОбщегоНазначенияКлиент.ДатаСеанса());
	
	Если Контекст.СертификатВерен <> Неопределено Тогда
		СвойстваПодписи.ДатаПроверкиПодписи = СвойстваПодписи.ДатаПодписи;
		СвойстваПодписи.ПодписьВерна = Контекст.СертификатВерен;
	КонецЕсли;
	
	СвойстваПодписи.ТребуетсяПроверка = Контекст.ТребуетсяПроверка;
	
	Возврат СвойстваПодписи;
	
КонецФункции

// Продолжение процедуры ВыполнитьНаСтороне.
Процедура ВыполнитьНаСторонеЦиклПослеПодписания(СвойстваПодписи, Контекст)
	
	ЭлементДанных = Контекст.ЭлементДанных;
	ЭлементДанных.Вставить("СвойстваПодписи", СвойстваПодписи);
	
	Если Не ЭлементДанных.Свойство("Объект") Тогда
		ЭлектроннаяПодписьСлужебныйВызовСервера.ЗарегистрироватьПодписаниеДанныхВЖурнале(
			СвойстваТекущегоЭлементаДанных(Контекст, СвойстваПодписи));
		ВыполнитьНаСторонеЦиклНачало(Контекст);
		Возврат;
	КонецЕсли;
	
	Если ТипЗнч(ЭлементДанных.Объект) <> Тип("ОписаниеОповещения") Тогда
		Если Контекст.НаСторонеКлиента Тогда
			ВерсияОбъекта = Неопределено;
			ЭлементДанных.Свойство("ВерсияОбъекта", ВерсияОбъекта);
			СвойстваПодписи.Вставить("ИдентификаторПодписи", Строка(Новый УникальныйИдентификатор));
			
			// Локализация
			
			Если ЗначениеЗаполнено(Контекст.ОписаниеДанных.РезультатПроверкиМЧДДляПодписания)
				И ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.МашиночитаемыеДоверенности") Тогда
				
				МодульМашиночитаемыеДоверенностиФНССлужебныйКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль(
					"МашиночитаемыеДоверенностиФНССлужебныйКлиент");
				РезультатПроверкиПодписиПоМЧД = МодульМашиночитаемыеДоверенностиФНССлужебныйКлиент.РезультатПроверкиПодписиПоМЧД(
					Контекст.ОписаниеДанных.ВыбраннаяДоверенность, ЭлементДанных.Объект,
					СвойстваПодписи.Сертификат, Неопределено, Контекст.ОписаниеДанных.РезультатПроверкиМЧДДляПодписания);
				Если ЗначениеЗаполнено(РезультатПроверкиПодписиПоМЧД) Тогда
					СвойстваПодписи.Вставить("РезультатПроверкиПодписиПоМЧД", РезультатПроверкиПодписиПоМЧД);
				КонецЕсли;
				
			КонецЕсли;
			
			// Конец Локализация
			
			ПредставлениеОшибки = ЭлектроннаяПодписьСлужебныйВызовСервера.ДобавитьПодпись(
				ЭлементДанных.Объект, СвойстваПодписи, Контекст.ИдентификаторФормы, ВерсияОбъекта);
			Если ЗначениеЗаполнено(ПредставлениеОшибки) Тогда
				ЭлементДанных.Удалить("СвойстваПодписи");
				ОшибкаНаКлиенте = Новый Структура("ОписаниеОшибки", ПредставлениеОшибки);
				ВыполнитьНаСторонеПослеЦикла(ОшибкаНаКлиенте, Контекст);
				Возврат;
			КонецЕсли;
		КонецЕсли;
		ОповеститьОбИзменении(ЭлементДанных.Объект);
		ВыполнитьНаСторонеЦиклНачало(Контекст);
		Возврат;
	КонецЕсли;
	
	ЭлектроннаяПодписьСлужебныйВызовСервера.ЗарегистрироватьПодписаниеДанныхВЖурнале(
		СвойстваТекущегоЭлементаДанных(Контекст, СвойстваПодписи));
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОписаниеДанных", Контекст.ОписаниеДанных);
	ПараметрыВыполнения.Вставить("Оповещение", Новый ОписаниеОповещения(
		"ВыполнитьНаСторонеЦиклПослеЗаписиПодписи", ЭтотОбъект, Контекст));
	
	Попытка
		ВыполнитьОбработкуОповещения(ЭлементДанных.Объект, ПараметрыВыполнения);
	Исключение
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		ВыполнитьНаСторонеЦиклПослеЗаписиПодписи(Новый Структура("ОписаниеОшибки",
			ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке)), Контекст);
	КонецПопытки;
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
Процедура ВыполнитьНаСторонеЦиклПослеЗаписиПодписи(Результат, Контекст) Экспорт
	
	Если Результат.Свойство("ОписаниеОшибки") Тогда
		Контекст.ЭлементДанных.Удалить("СвойстваПодписи");
		Ошибка = Новый Структура("ОписаниеОшибки",
			НСтр("ru = 'При записи подписи возникла ошибка:'") + Символы.ПС + Результат.ОписаниеОшибки);
		ВыполнитьНаСторонеПослеЦикла(Ошибка, Контекст);
		Возврат;
	КонецЕсли;
	
	ВыполнитьНаСторонеЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
Процедура ВыполнитьНаСторонеЦиклПослеШифрования(ЗашифрованныеДанные, Контекст)
	
	ЭлементДанных = Контекст.ЭлементДанных;
	ЭлементДанных.Вставить("ЗашифрованныеДанные", ЗашифрованныеДанные);
	
	Если Не ЭлементДанных.Свойство("РазмещениеРезультата")
	 Или ТипЗнч(ЭлементДанных.РазмещениеРезультата) <> Тип("ОписаниеОповещения") Тогда
		
		ВыполнитьНаСторонеЦиклНачало(Контекст);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОписаниеДанных", Контекст.ОписаниеДанных);
	ПараметрыВыполнения.Вставить("Оповещение", Новый ОписаниеОповещения(
		"ВыполнитьНаСторонеЦиклПослеЗаписиЗашифрованныхДанных", ЭтотОбъект, Контекст));
	
	Попытка
		ВыполнитьОбработкуОповещения(ЭлементДанных.РазмещениеРезультата, ПараметрыВыполнения);
	Исключение
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		ВыполнитьНаСторонеЦиклПослеЗаписиЗашифрованныхДанных(Новый Структура("ОписаниеОшибки",
			ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке)), Контекст);
	КонецПопытки;
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
Процедура ВыполнитьНаСторонеЦиклПослеЗаписиЗашифрованныхДанных(Результат, Контекст) Экспорт
	
	Если Результат.Свойство("ОписаниеОшибки") Тогда
		Контекст.ЭлементДанных.Удалить("ЗашифрованныеДанные");
		Ошибка = Новый Структура("ОписаниеОшибки",
			НСтр("ru = 'Не удалось записать зашифрованные данные по причине:'")
			+ Символы.ПС + Результат.ОписаниеОшибки);
		ВыполнитьНаСторонеПослеЦикла(Ошибка, Контекст);
		Возврат;
	КонецЕсли;
	
	ВыполнитьНаСторонеЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
Процедура ВыполнитьНаСторонеЦиклПослеРасшифровки(РасшифрованныеДанные, Контекст)
	
	ЭлементДанных = Контекст.ЭлементДанных;
	ЭлементДанных.Вставить("РасшифрованныеДанные", РасшифрованныеДанные);
	
	Если Не ЭлементДанных.Свойство("РазмещениеРезультата")
	 Или ТипЗнч(ЭлементДанных.РазмещениеРезультата) <> Тип("ОписаниеОповещения") Тогда
	
		ВыполнитьНаСторонеЦиклНачало(Контекст);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОписаниеДанных", Контекст.ОписаниеДанных);
	ПараметрыВыполнения.Вставить("Оповещение", Новый ОписаниеОповещения(
		"ВыполнитьНаСторонеЦиклПослеЗаписиРасшифрованныхДанных", ЭтотОбъект, Контекст));
	
	Попытка
		ВыполнитьОбработкуОповещения(ЭлементДанных.РазмещениеРезультата, ПараметрыВыполнения);
	Исключение
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		ВыполнитьНаСторонеЦиклПослеЗаписиЗашифрованныхДанных(Новый Структура("ОписаниеОшибки",
			ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке)), Контекст);
	КонецПопытки;
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
Процедура ВыполнитьНаСторонеЦиклПослеЗаписиРасшифрованныхДанных(Результат, Контекст) Экспорт
	
	Если Результат.Свойство("ОписаниеОшибки") Тогда
		Контекст.ЭлементДанных.Удалить("РасшифрованныеДанные");
		Ошибка = Новый Структура("ОписаниеОшибки",
			НСтр("ru = 'Не удалось записать расшифрованные данные по причине:'")
			+ Символы.ПС + Результат.ОписаниеОшибки);
		ВыполнитьНаСторонеПослеЦикла(Ошибка, Контекст);
		Возврат;
	КонецЕсли;
	
	ВыполнитьНаСторонеЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
Процедура ВыполнитьНаСторонеПослеЦикла(Ошибка, Контекст)
	
	Результат = Новый Структура;
	Если Ошибка <> Неопределено Тогда
		Результат.Вставить("Ошибка", Ошибка);
	КонецЕсли;
	
	Если Контекст.ОперацияНачалась Тогда
		Результат.Вставить("ОперацияНачалась");
		
		Если Не Результат.Свойство("Ошибка") И Контекст.Индекс > 0 Тогда
			Результат.Вставить("ЕстьОбработанныеЭлементыДанных");
		КонецЕсли;
	КонецЕсли;
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
	
КонецПроцедуры

// Возвращаемое значение:
//  Структура:
//   * Оповещение - ОписаниеОповещения
//   * Операция - Строка
//   * НаСторонеКлиента - Булево
//   * ОперацияНачалась - Булево
//   * ОписаниеДанных - Структура
//   * Форма - ФормаКлиентскогоПриложения
//   * ИдентификаторФормы - УникальныйИдентификатор
//   * ЗначениеПароля - Строка
//   * СертификатВерен - Неопределено
//                     - Булево
//   * ТребуетсяПроверка - Неопределено
//                       - Булево
//   * СертификатАдрес - Строка
//   * ТекущийСписокПредставлений - СписокЗначений
//                                - Массив
//   * ПолноеПредставлениеДанных - Строка
//   * МенеджерКриптографии - МенеджерКриптографии
//                          - Строка
//   * СертификатКриптографии - СертификатКриптографии
//   * Индекс - Число
//   * СвойстваСертификатов - Структура
//   * СертификатыШифрования - Массив
//
Функция ВыполнитьНаСторонеНовыйКонтекст()
	
	Возврат Новый Структура("ОписаниеДанных, Форма, ИдентификаторФормы, ЗначениеПароля,
		|СертификатВерен, ТребуетсяПроверка, СертификатАдрес, ТекущийСписокПредставлений, ПолноеПредставлениеДанных");
	
КонецФункции

// Только для внутреннего использования.
Функция СвойстваТекущегоЭлементаДанных(ПараметрыВыполнения, СвойстваПодписи = Неопределено) Экспорт
	
	Если ПараметрыВыполнения.ОписаниеДанных.Свойство("Данные")
	 Или Не ПараметрыВыполнения.ОписаниеДанных.Свойство("ТекущийЭлементНабораДанных") Тогда
		
		ПредставлениеЭлементаДанных = ПараметрыВыполнения.ТекущийСписокПредставлений[0].Значение;
	Иначе
		ПредставлениеЭлементаДанных = ПараметрыВыполнения.ТекущийСписокПредставлений[
			ПараметрыВыполнения.ОписаниеДанных.НаборДанных.Найти(
				ПараметрыВыполнения.ОписаниеДанных.ТекущийЭлементНабораДанных)].Значение;
	КонецЕсли;
	
	Если ТипЗнч(ПредставлениеЭлементаДанных) = Тип("ОписаниеОповещения") Тогда
		ПредставлениеЭлементаДанных = ПараметрыВыполнения.ПолноеПредставлениеДанных;
	КонецЕсли;
	
	Если СвойстваПодписи = Неопределено Тогда
		СвойстваПодписи = Новый Структура;
		СвойстваПодписи.Вставить("Сертификат",  ПараметрыВыполнения.СертификатАдрес);
		СвойстваПодписи.Вставить("ДатаПодписи", '00010101');
	КонецЕсли;
	
	СвойстваЭлементаДанных = Новый Структура;
	
	СвойстваЭлементаДанных.Вставить("СвойстваПодписи",     СвойстваПодписи);
	СвойстваЭлементаДанных.Вставить("ПредставлениеДанных", ПредставлениеЭлементаДанных);
	
	Возврат СвойстваЭлементаДанных;
	
КонецФункции

// Только для внутреннего использования.
Процедура ПолучитьДанныеИзОписанияДанных(Оповещение, Форма, ОписаниеДанных, ИсточникДанных, ДляСтороныКлиента) Экспорт
	
	Контекст = Новый Структура;
	Контекст.Вставить("Форма", Форма);
	Контекст.Вставить("Оповещение", Оповещение);
	Контекст.Вставить("ДляСтороныКлиента", ДляСтороныКлиента);
	
	Если ТипЗнч(ИсточникДанных) = Тип("ОписаниеОповещения") Тогда
		ПараметрыВыполнения = Новый Структура;
		ПараметрыВыполнения.Вставить("ОписаниеДанных", ОписаниеДанных);
		ПараметрыВыполнения.Вставить("Оповещение",  Новый ОписаниеОповещения(
			"ПолучитьДанныеИзОписанияДанныхПродолжение", ЭтотОбъект, Контекст));
		
		Попытка
			ВыполнитьОбработкуОповещения(ИсточникДанных, ПараметрыВыполнения);
		Исключение
			ИнформацияОбОшибке = ИнформацияОбОшибке();
			Результат = Новый Структура("ОписаниеОшибки", ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
			ПолучитьДанныеИзОписанияДанныхПродолжение(Результат, Контекст);
		КонецПопытки;
	Иначе
		ПолучитьДанныеИзОписанияДанныхПродолжение(Новый Структура("Данные", ИсточникДанных), Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ПолучитьДанныеИзОписанияДанных.
Процедура ПолучитьДанныеИзОписанияДанныхПродолжение(Результат, Контекст) Экспорт
	
	ЭтоXMLDSig = (ТипЗнч(Результат) = Тип("Структура")
	            И Результат.Свойство("Данные")
	            И ТипЗнч(Результат.Данные) = Тип("Структура")
	            И Результат.Данные.Свойство("ПараметрыXMLDSig"));
	
	Если ЭтоXMLDSig И Не Результат.Данные.Свойство("КонвертXML") Тогда
		Результат.Данные = Новый Структура(Новый ФиксированнаяСтруктура(Результат.Данные));
		Результат.Данные.Вставить("КонвертXML", Результат.Данные.КонвертSOAP);
	КонецЕсли;
	
	ЭтоCMS = (ТипЗнч(Результат) = Тип("Структура")
	       И Результат.Свойство("Данные")
	       И ТипЗнч(Результат.Данные) = Тип("Структура")
	       И Результат.Данные.Свойство("ПараметрыCMS"));
	
	Если ТипЗнч(Результат) <> Тип("Структура")
	 Или Не Результат.Свойство("Данные")
	 Или ТипЗнч(Результат.Данные) <> Тип("ДвоичныеДанные")
	   И ТипЗнч(Результат.Данные) <> Тип("Строка")
	   И Не ЭтоXMLDSig
	   И Не ЭтоCMS Тогда
		
		Если ТипЗнч(Результат) <> Тип("Структура") Или Не Результат.Свойство("ОписаниеОшибки") Тогда
			Ошибка = Новый Структура("ОписаниеОшибки", НСтр("ru = 'Некорректный тип данных.'"));
		Иначе
			Ошибка = Новый Структура("ОписаниеОшибки", Результат.ОписаниеОшибки);
		КонецЕсли;
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Ошибка);
		Возврат;
	КонецЕсли;
	
	Данные = Результат.Данные;
	
	Если Контекст.ДляСтороныКлиента Тогда
		// Для стороны клиента требуются двоичные данные или путь к файлу.
		
		Если ТипЗнч(Данные) = Тип("ДвоичныеДанные")
			Или ЭтоXMLDSig
			Или ЭтоCMS Тогда
			
			ВыполнитьОбработкуОповещения(Контекст.Оповещение, Данные);
			
		ИначеЕсли ЭтоАдресВременногоХранилища(Данные) Тогда
			Попытка
				ТекущийРезультат = ПолучитьИзВременногоХранилища(Данные);
			Исключение
				ИнформацияОбОшибке = ИнформацияОбОшибке();
				ТекущийРезультат = Новый Структура("ОписаниеОшибки",
					ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
			КонецПопытки;
			ВыполнитьОбработкуОповещения(Контекст.Оповещение, ТекущийРезультат);
			
		Иначе // Путь к файлу
			ВыполнитьОбработкуОповещения(Контекст.Оповещение, Данные);
		КонецЕсли;
	Иначе
		// Для стороны сервера требуется адрес двоичных данных во временном хранилище.
		
		Если ТипЗнч(Данные) = Тип("ДвоичныеДанные")
			Или ЭтоXMLDSig Тогда
			
			ВыполнитьОбработкуОповещения(Контекст.Оповещение,
				ПоместитьВоВременноеХранилище(Данные, Контекст.Форма.УникальныйИдентификатор));
			
		ИначеЕсли ЭтоCMS Тогда
			
			Данные.ПараметрыCMS.ВключениеСертификатовВПодпись =
				ВключениеСертификатовВПодписьСтрокой(
					Данные.ПараметрыCMS.ВключениеСертификатовВПодпись);
			
			ВыполнитьОбработкуОповещения(Контекст.Оповещение,
				ПоместитьВоВременноеХранилище(Данные, Контекст.Форма.УникальныйИдентификатор));
			
		ИначеЕсли ЭтоАдресВременногоХранилища(Данные) Тогда
			ВыполнитьОбработкуОповещения(Контекст.Оповещение, Данные);
			
		Иначе // Путь к файлу
			Попытка
				ПараметрыЗагрузки = ФайловаяСистемаКлиент.ПараметрыЗагрузкиФайла();
				ПараметрыЗагрузки.ИдентификаторФормы = Контекст.Форма.УникальныйИдентификатор;
				ПараметрыЗагрузки.Интерактивно = Ложь;
				ФайловаяСистемаКлиент.ЗагрузитьФайл(Новый ОписаниеОповещения(
					"ПолучитьДанныеИзОписанияДанныхЗавершение", ЭтотОбъект, Контекст,
					"ПолучитьДанныеИзОписанияДанныхЗавершениеПоОшибке", ЭтотОбъект),
					ПараметрыЗагрузки, Данные); 
			Исключение
				ИнформацияОбОшибке = ИнформацияОбОшибке();
				ТекущийРезультат = Новый Структура("ОписаниеОшибки",
					ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
				ВыполнитьОбработкуОповещения(Контекст.Оповещение, ТекущийРезультат);
			КонецПопытки;
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ПолучитьДанныеИзОписанияДанных.
Процедура ПолучитьДанныеИзОписанияДанныхЗавершениеПоОшибке(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
	
	СтандартнаяОбработка = Ложь;
	
	Результат = Новый Структура("ОписаниеОшибки", ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
	
КонецПроцедуры

// Продолжение процедуры ПолучитьДанныеИзОписанияДанных.
Процедура ПолучитьДанныеИзОписанияДанныхЗавершение(ПомещенныеФайлы, Контекст) Экспорт
	
	Если ПомещенныеФайлы = Неопределено Или ПомещенныеФайлы.Количество() = 0 Тогда
		Результат = Новый Структура("ОписаниеОшибки",
			НСтр("ru = 'Передача данных отменена пользователем.'"));
	Иначе
		Результат = ПомещенныеФайлы[0].Хранение;
	КонецЕсли;
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
	
КонецПроцедуры

// Только для внутреннего использования.
Процедура ПродлитьХранениеКонтекстаОперации(ОписаниеДанных) Экспорт
	
	ФормаПередачаПараметров().ПродлитьХранениеКонтекстаОперации(ОписаниеДанных.КонтекстОперации);
	
КонецПроцедуры

#Область УсовершенствоватьПодпись

Процедура УсовершенствоватьПодпись(Контекст) Экспорт
	
	Если Не ЭлектроннаяПодписьКлиент.ОбщиеНастройки().ДоступнаУсовершенствованнаяПодпись Тогда
		ВызватьИсключение НСтр("ru='Усовершенствование подписи недоступно на текущей версии платформы.'");
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(Контекст.ПараметрыВыполнения.ОписаниеДанных.Подпись) Тогда
		ВызватьИсключение НСтр("ru='Переданные параметры не содержат данных подписи.'");
	КонецЕсли;
	
	Если ЭлектроннаяПодписьКлиент.ОбщиеНастройки().ЭтоМодельСервисаСДоступнымУсовершенствованием 
		И Контекст.ПараметрыВыполнения.ОписаниеДанных.ТипПодписи = 
			ПредопределенноеЗначение("Перечисление.ТипыПодписиКриптографии.СМеткойДоверенногоВремениCAdEST") Тогда
		
		НастройкиПодключенияСервиса = 
			ЭлектроннаяПодписьСлужебныйВызовСервера.НастройкиСлужебнойУчетнойЗаписиДляУсовершенствованияПодписей(
				Контекст.ПараметрыВыполнения.ИдентификаторФормы);
		Если ЗначениеЗаполнено(НастройкиПодключенияСервиса.Ошибка) Тогда
			ОписаниеОповещения = Новый ОписаниеОповещения("ПродолжитьУсовершенствованиеПослеОтветаНаВопрос", ЭтотОбъект, Контекст);
			ТекстВопроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru='Ошибка при попытке усовершенствования через приложение в Интернете:
				|%1
				|Продолжить усовершенствование с помощью программ, установленных на компьютере?'"),
				НастройкиПодключенияСервиса.Ошибка);
			ПоказатьВопрос(ОписаниеОповещения, ТекстВопроса, РежимДиалогаВопрос.ДаНет, 60);
			Возврат;
		КонецЕсли;
		
		Контекст.ПараметрыВыполнения.Вставить("ЭтоМодельСервисаСДоступнымУсовершенствованием", Истина);
		Контекст.ПараметрыВыполнения.Вставить("СлужебнаяУчетнаяЗаписьDSS", НастройкиПодключенияСервиса.СлужебнаяУчетнаяЗаписьDSS);
		Контекст.ПараметрыВыполнения.Вставить("ПараметрыПодписиCAdEST", НастройкиПодключенияСервиса.ПараметрыПодписиCAdEST);
		
		УсовершенствоватьНаСтороне(Новый ОписаниеОповещения(
			"УсовершенствоватьПослеВыполненияНаСторонеСервера", ЭлектроннаяПодписьСлужебныйКлиент, Контекст),
			"НаСторонеСервера", Контекст.ПараметрыВыполнения);

	ИначеЕсли ЭлектроннаяПодписьКлиент.СоздаватьЭлектронныеПодписиНаСервере() Тогда
		УсовершенствоватьНаСтороне(Новый ОписаниеОповещения(
			"УсовершенствоватьПослеВыполненияНаСторонеСервера", ЭлектроннаяПодписьСлужебныйКлиент, Контекст),
			"НаСторонеСервера", Контекст.ПараметрыВыполнения);
	Иначе
		УсовершенствоватьПослеВыполненияНаСторонеСервера(Неопределено, Контекст);
	КонецЕсли;
	
КонецПроцедуры 

Процедура ПродолжитьУсовершенствованиеПослеОтветаНаВопрос(РезультатВопроса, Контекст) Экспорт
	
	Если РезультатВопроса = КодВозвратаДиалога.Да Тогда
		УсовершенствоватьПослеВыполненияНаСторонеСервера(Неопределено, Контекст);
	Иначе
		Результат = Новый Структура;
		Результат.Вставить("Ошибка", Истина);
		Результат.Вставить("ТекстОшибки", НСтр("ru='Ошибка при попытке усовершенствования через приложение в Интернете'"));
		УсовершенствоватьПослеВыполненияНаСторонеКлиента(Результат, Контекст);
	КонецЕсли;
	
КонецПроцедуры

Процедура УсовершенствоватьНаСтороне(Оповещение, СторонаВыполнения, ПараметрыВыполнения)

	Контекст = Новый Структура("ОписаниеДанных, ИдентификаторФормы");
	Контекст.Вставить("ПрерыватьОбработкуМассиваПриОшибке",  Истина);
	Контекст.Вставить("ИгнорироватьСрокДействияСертификата", Ложь);
	ЗаполнитьЗначенияСвойств(Контекст, ПараметрыВыполнения);
	
	Если ПараметрыВыполнения.Свойство("ЭтоМодельСервисаСДоступнымУсовершенствованием") Тогда
		Контекст.Вставить("ЭтоМодельСервисаСДоступнымУсовершенствованием", Истина);
		Контекст.Вставить("СлужебнаяУчетнаяЗаписьDSS", ПараметрыВыполнения.СлужебнаяУчетнаяЗаписьDSS);
		Контекст.Вставить("ПараметрыПодписиCAdEST", ПараметрыВыполнения.ПараметрыПодписиCAdEST);
	Иначе
		Контекст.Вставить("ЭтоМодельСервисаСДоступнымУсовершенствованием", Ложь);
	КонецЕсли;
	
	Контекст.Вставить("Оповещение",       Оповещение);
	Контекст.Вставить("НаСторонеКлиента", СторонаВыполнения = "НаСторонеКлиента");
	Контекст.Вставить("ОперацияНачалась", Ложь);
	Контекст.Вставить("ЕстьОшибки", Ложь);
	Контекст.Вставить("ОшибкиСозданияМенеджераКриптографии", Новый Массив);
	
	Если ПараметрыВыполнения.Свойство("ЭлементыДанных") Тогда
		Контекст.Вставить("ЭлементыДанных", ПараметрыВыполнения.ЭлементыДанных);
	Иначе
		Если ТипЗнч(Контекст.ОписаниеДанных.Подпись) = Тип("Массив") Тогда
			Подписи = Контекст.ОписаниеДанных.Подпись;
		Иначе
			Подписи = Новый Массив;
			Подписи.Добавить(Контекст.ОписаниеДанных.Подпись);
		КонецЕсли;
		
		ТипЭлементовДанных = ТипЗнч(Подписи[0]); // Все должны быть однотипными.
		
		Если ТипЭлементовДанных = Тип("Структура") Тогда
			ЭлементыДанных = ЭлектроннаяПодписьСлужебныйВызовСервера.ПреобразоватьПодписиВМассив(Подписи,
				Контекст.ИдентификаторФормы);
		Иначе
			ЭлементыДанных = Новый Массив;
			Для Каждого ТекущийЭлемент Из Подписи Цикл
				ЭлементыДанных.Добавить(Новый Структура("Подпись, ТипПодписи, СрокДействияПоследнейМеткиВремени", ТекущийЭлемент));
			КонецЦикла;
		КонецЕсли;
		Контекст.Вставить("ЭлементыДанных", ЭлементыДанных);
	КонецЕсли;
	
	Контекст.Вставить("Индекс", -1);
	УсовершенствоватьНаСторонеЦиклНачало(Контекст);
	
КонецПроцедуры 

// Продолжение процедуры УсовершенствоватьНаСтороне.
// 
// Параметры:
//  Контекст - Структура:
//   * Индекс - Число
//
Процедура УсовершенствоватьНаСторонеЦиклНачало(Контекст)
	
	Если Контекст.ЭлементыДанных.Количество() <= Контекст.Индекс + 1 Тогда
		УсовершенствоватьНаСторонеПослеЦикла(Контекст);
		Возврат;
	КонецЕсли;
	
	Оповещение = Новый ОписаниеОповещения(
		"УсовершенствоватьНаСторонеЦиклНачалоПродолжение", ЭтотОбъект, Контекст);
	
	СтандартныеПодсистемыКлиент.НачатьВыполнениеОбработкиОповещения(Оповещение);
	
КонецПроцедуры

// Продолжение процедуры УсовершенствоватьНаСтороне.
// 
// Параметры:
//  Контекст - Структура:
//   * Индекс - Число
//
Процедура УсовершенствоватьНаСторонеЦиклНачалоПродолжение(Результат, Контекст) Экспорт
	
	Контекст.Индекс = Контекст.Индекс + 1;
	ЭлементДанных = Контекст.ЭлементыДанных[Контекст.Индекс];
	
	Если ЭлементДанных.Свойство("СвойстваПодписи") Тогда
		УсовершенствоватьНаСторонеЦиклНачало(Контекст);
		Возврат;
	КонецЕсли;
	
	Контекст.Вставить("ЭлементДанных", ЭлементДанных);
	
	Подпись = ЭлементДанных.Подпись;
		
	Если Контекст.НаСторонеКлиента Тогда
		// Для стороны клиента требуются двоичные данные. 
		Если ТипЗнч(Подпись) = Тип("Строка") Тогда
			Попытка
				Подпись = ПолучитьИзВременногоХранилища(Подпись);
			Исключение
				Ошибка = ОписаниеОшибкиПриУсовершенствовании();
				Ошибка.Текст = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
				УсовершенствоватьНаСторонеПослеОшибки(Ошибка, Контекст);
				Возврат;
			КонецПопытки;
		КонецЕсли;
		
		ЭлементДанных.Подпись = Подпись;

		ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
		ПараметрыСоздания.ПоказатьОшибку = Неопределено;
		Если ЭлементДанных.Свойство("АлгоритмПодписи") Тогда
			ПараметрыСоздания.АлгоритмПодписи = ЭлементДанных.АлгоритмПодписи;
		Иначе
			ПараметрыСоздания.АлгоритмПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.АлгоритмСформированнойПодписи(Подпись);
			Контекст.ЭлементыДанных[Контекст.Индекс].Вставить("АлгоритмПодписи", ПараметрыСоздания.АлгоритмПодписи);
		КонецЕсли;
		
		СоздатьМенеджерКриптографии(Новый ОписаниеОповещения(
			"УсовершенствоватьНаСторонеПослеСозданияМенеджераКриптографии", ЭтотОбъект, Контекст),
			"ПродлениеСрокаДействияПодписи", ПараметрыСоздания);

		Возврат;
		
	КонецЕсли;
	
	УсовершенствоватьНаСервере(ЭлементДанных, Контекст);

КонецПроцедуры 

// Продолжение процедуры УсовершенствоватьНаСтороне.
Процедура УсовершенствоватьНаСервере(ЭлементДанных, Контекст)

	Подпись = Контекст.ЭлементДанных.Подпись;

	ПараметрыДляСервера = Новый Структура;
	ПараметрыДляСервера.Вставить("ЭтоМодельСервисаСДоступнымУсовершенствованием",
		Контекст.ЭтоМодельСервисаСДоступнымУсовершенствованием);
		
	ПараметрыДляСервера.Вставить("ИдентификаторФормы", Контекст.ИдентификаторФормы);
	ПараметрыДляСервера.Вставить("ЭлементДанныхДляСервера", ЭлементДанных);
	ПараметрыДляСервера.Вставить("ТипПодписи", Контекст.ОписаниеДанных.ТипПодписи);
	ПараметрыДляСервера.Вставить("ДобавитьАрхивнуюМеткуВремени", Контекст.ОписаниеДанных.ДобавитьАрхивнуюМеткуВремени);
	ПараметрыДляСервера.Вставить("ОперацияНачалась", Контекст.ОперацияНачалась);
	ПараметрыДляСервера.Вставить("ИгнорироватьСрокДействияСертификата", Контекст.ИгнорироватьСрокДействияСертификата);
	
	Если ПараметрыДляСервера.ЭтоМодельСервисаСДоступнымУсовершенствованием Тогда
		
		ПараметрыДляСервера.ЭлементДанныхДляСервера.Подпись = Подпись;
		ПараметрыДляСервера.Вставить("ПараметрыПодписиCAdEST", Контекст.ПараметрыПодписиCAdEST);
		ПараметрыДляСервера.Вставить("СлужебнаяУчетнаяЗаписьDSS", Контекст.СлужебнаяУчетнаяЗаписьDSS);
		
		ДлительнаяОперация = ЭлектроннаяПодписьСлужебныйВызовСервера.НачатьУсовершенствованиеНаСервере(
			ПараметрыДляСервера);
			
		Если Не ДлительнаяОперация.Свойство("АдресРезультата") Тогда
			ПродолжитьПослеУсовершенствованияНаСервере(ДлительнаяОперация, Контекст);
			Возврат;
		КонецЕсли;
		
		ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(Неопределено);
		ПараметрыОжидания.ВыводитьОкноОжидания = Истина;
		
		ОповещениеОЗавершении = Новый ОписаниеОповещения("ПродолжитьПослеУсовершенствованияНаСервере", ЭтотОбъект, Контекст);
		ДлительныеОперацииКлиент.ОжидатьЗавершение(ДлительнаяОперация, ОповещениеОЗавершении, ПараметрыОжидания);
	Иначе
		// Для стороны сервера требуется адрес двоичных данных во временном хранилище.
		Если ТипЗнч(Подпись) = Тип("ДвоичныеДанные") Тогда
			ПараметрыДляСервера.ЭлементДанныхДляСервера.Подпись = ПоместитьВоВременноеХранилище(Подпись, Контекст.ИдентификаторФормы);
		КонецЕсли;
		
		Результат = ЭлектроннаяПодписьСлужебныйВызовСервера.УсовершенствоватьНаСторонеСервера(ПараметрыДляСервера);
		ПродолжитьПослеУсовершенствованияНаСервере(Результат, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры УсовершенствоватьНаСтороне.
// 
// Параметры:
//  Контекст - Структура
//
Процедура ПродолжитьПослеУсовершенствованияНаСервере(РезультатВыполнения, Контекст) Экспорт
	
	Если РезультатВыполнения.Свойство("АдресРезультата") Тогда
		// Результат выполнения фонового задания.
		Результат = ПолучитьИзВременногоХранилища(РезультатВыполнения.АдресРезультата); 
		УдалитьИзВременногоХранилища(РезультатВыполнения.АдресРезультата);
		Если ЗначениеЗаполнено(РезультатВыполнения.КраткоеПредставлениеОшибки) Тогда
			ОшибкаНаСервере = ОписаниеОшибкиПриУсовершенствовании(Ложь);
			ОшибкаНаСервере.Текст = РезультатВыполнения.КраткоеПредставлениеОшибки;
			УсовершенствоватьНаСторонеПослеОшибки(ОшибкаНаСервере, Контекст);
			Возврат;
		КонецЕсли;
	Иначе
		Результат = РезультатВыполнения;
	КонецЕсли;
	
	Контекст.ОперацияНачалась = Результат.ОперацияНачалась;
	
	Если Результат.Свойство("АлгоритмПодписи") И ЗначениеЗаполнено(Результат.АлгоритмПодписи) Тогда
		Контекст.ЭлементыДанных[Контекст.Индекс].Вставить("АлгоритмПодписи", Результат.АлгоритмПодписи);
	КонецЕсли;
	
	Если Не Результат.Успех Тогда
		ОшибкаНаСервере = ОписаниеОшибкиПриУсовершенствовании(Ложь);
		ОшибкаНаСервере.Текст = Результат.ТекстОшибки;
		Если Результат.ОшибкаПриСозданииМенеджераКриптографии = Истина Тогда
			ОшибкаНаСервере.ОшибкаПриСозданииМенеджераКриптографии = Истина;
		КонецЕсли;
		УсовершенствоватьНаСторонеПослеОшибки(ОшибкаНаСервере, Контекст);
	Иначе
		ВыполнитьНаСторонеЦиклПослеУсовершенствования(Результат.СвойстваПодписи, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры УсовершенствоватьНаСтороне.
Процедура УсовершенствоватьНаСторонеПослеСозданияМенеджераКриптографии(МенеджерКриптографии, Контекст) Экспорт
	
	Если ТипЗнч(МенеджерКриптографии) <> Тип("МенеджерКриптографии") Тогда
		Ошибка = ОписаниеОшибкиПриУсовершенствовании();
		Ошибка.Текст = МенеджерКриптографии.ОписаниеОшибки;
		Ошибка.ОшибкаСозданияМенеджераКриптографии = Истина;
		УсовершенствоватьНаСторонеПослеОшибки(Ошибка, Контекст);
		Возврат;
	КонецЕсли;
	
	Контекст.Вставить("МенеджерКриптографии", МенеджерКриптографии);
	Подпись = Контекст.ЭлементДанных.Подпись;
	
	Оповещение = Новый ОписаниеОповещения("УсовершенствоватьНаСторонеПослеПолученияКонтейнераПодписи", ЭтотОбъект, Контекст,
		"УсовершенствоватьНаСторонеЦиклПослеОшибкиОперацииНаКлиенте", ЭтотОбъект);
	МенеджерКриптографии.НачатьПолучениеКонтейнераПодписейКриптографии(Оповещение, Подпись);

КонецПроцедуры

// Продолжение процедуры УсовершенствоватьНаСтороне.
Асинх Процедура УсовершенствоватьНаСторонеПослеПолученияКонтейнераПодписи(КонтейнерПодписи, Контекст) Экспорт
	
	ДатаСеанса = ОбщегоНазначенияКлиент.ДатаСеанса();
	ДобавкаВремени = ДатаСеанса - ОбщегоНазначенияКлиент.ДатаУниверсальная();
	ПараметрыПодписи = Ждать ПараметрыПодписиКриптографии(
		КонтейнерПодписи, ДобавкаВремени, ДатаСеанса);
	
	Контекст.ЭлементДанных.Вставить("ПараметрыПодписи", ПараметрыПодписи);
	
	Если ПараметрыПодписи.СертификатПоследнейМеткиВремени = Неопределено Тогда
		ОписаниеОшибки = НСтр("ru='Не удалось получить сертификат подписи'");
		Контекст.ЭлементДанных.Вставить("Ошибка", ОписаниеОшибки);
		УсовершенствоватьНаСторонеЦиклПослеОперацииНаКлиенте(ПараметрыПодписи, Контекст);
		Возврат;
	КонецЕсли;
	
	Если Не Контекст.ИгнорироватьСрокДействияСертификата
		И ЗначениеЗаполнено(ПараметрыПодписи.СрокДействияПоследнейМеткиВремени)
		И ПараметрыПодписи.СрокДействияПоследнейМеткиВремени < ДатаСеанса Тогда 
		
		ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru='Истек срок действия сертификата подписи: %1'"),
			СвойстваСертификатаСтрокой(ПараметрыПодписи.СертификатПоследнейМеткиВремени));
		Контекст.ЭлементДанных.Вставить("Ошибка", ОписаниеОшибки);
		УсовершенствоватьНаСторонеЦиклПослеОперацииНаКлиенте(ПараметрыПодписи, Контекст);
		
		Возврат;
	КонецЕсли;
	
	Если ПараметрыПодписи.СертификатПоследнейМеткиВремени <> Неопределено Тогда
		Оповещение = Новый ОписаниеОповещения("УсовершенствоватьНаСторонеПослеПроверкиСертификатаПодписи", ЭтотОбъект, Контекст); 
		ПроверитьСертификат(Оповещение, ПараметрыПодписи.СертификатПоследнейМеткиВремени, Контекст.МенеджерКриптографии);
	Иначе
		УсовершенствоватьНаСторонеПослеПроверкиСертификатаПодписи(Истина, Контекст);
	КонецЕсли;

КонецПроцедуры

// Продолжение процедуры УсовершенствоватьНаСтороне.
Процедура УсовершенствоватьНаСторонеПослеПроверкиСертификатаПодписи(Результат, Контекст) Экспорт
	
	ПараметрыПодписи = Контекст.ЭлементДанных.ПараметрыПодписи;
	
	Если Результат <> Истина Тогда
		Ошибка = ОписаниеОшибкиПриУсовершенствовании();
		Ошибка.Текст = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru='При проверке сертификата подписи до усовершенствования: %1
			|%2'"), Результат, СвойстваСертификатаСтрокой(ПараметрыПодписи.СертификатПоследнейМеткиВремени));
		УсовершенствоватьНаСторонеПослеОшибки(Ошибка, Контекст);
		Возврат;
	КонецЕсли;
	
	Оповещение = Новый ОписаниеОповещения(
		"УсовершенствоватьНаСторонеЦиклПослеОперацииНаКлиенте", ЭтотОбъект, Контекст,
		"УсовершенствоватьНаСторонеЦиклПослеОшибкиОперацииНаКлиенте", ЭтотОбъект); 
	
	МенеджерКриптографии = Контекст.МенеджерКриптографии;
	МенеджерКриптографии.АдресаСерверовМетокВремени = 
		ЭлектроннаяПодписьКлиент.ОбщиеНастройки().АдресаСерверовМетокВремени;
		
	Подпись = Контекст.ЭлементДанных.Подпись;
	
	Если ПараметрыПодписи.ТипПодписи = ПредопределенноеЗначение("Перечисление.ТипыПодписиКриптографии.АрхивнаяCAdESAv3")
		Или ПараметрыПодписи.ТипПодписи = ПредопределенноеЗначение("Перечисление.ТипыПодписиКриптографии.CAdESAv2") Тогда
		Если Контекст.ОписаниеДанных.ДобавитьАрхивнуюМеткуВремени Тогда
			МенеджерКриптографии.НачатьДобавлениеАрхивнойМеткиВремени(Оповещение, Подпись);
		Иначе
			УсовершенствоватьНаСторонеЦиклПослеОперацииНаКлиенте(ПараметрыПодписи, Контекст);
			Возврат;
		КонецЕсли;
	ИначеЕсли ЗначениеЗаполнено(Контекст.ОписаниеДанных.ТипПодписи)
		И ЭлектроннаяПодписьСлужебныйКлиентСервер.ПодлежитУсовершенствованию(ПараметрыПодписи.ТипПодписи, Контекст.ОписаниеДанных.ТипПодписи) Тогда
			МенеджерКриптографии.НачатьУсовершенствованиеПодписи(Оповещение, Подпись,
				ЭлектроннаяПодписьСлужебныйКлиентСервер.ТипПодписиКриптографии(Контекст.ОписаниеДанных.ТипПодписи));
	Иначе
		УсовершенствоватьНаСторонеЦиклПослеОперацииНаКлиенте(ПараметрыПодписи, Контекст);
		Возврат;
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры УсовершенствоватьНаСтороне.
// 
// Параметры:
//   ДвоичныеДанные - ДвоичныеДанные
//                  - Структура - параметры подписи, не подлежащей усовершенствованию.
//   Контекст - Структура
//
Процедура УсовершенствоватьНаСторонеЦиклПослеОперацииНаКлиенте(ДвоичныеДанные, Контекст) Экспорт
	
	Если ТипЗнч(ДвоичныеДанные) = Тип("Структура") Тогда 
		// Подпись не продлевалась, возможно, нужно записать параметры переданной подписи.
		Контекст.ЭлементДанных.Вставить("НеТребуетсяПродление", Истина);
		ВыполнитьНаСторонеЦиклПослеУсовершенствования(ДвоичныеДанные, Контекст);
		Возврат;
	КонецЕсли;
		
	ОписаниеОшибки = "";
	Если ЭлектроннаяПодписьСлужебныйКлиентСервер.ПустыеДанныеПодписи(ДвоичныеДанные, ОписаниеОшибки) Тогда
		Ошибка = ОписаниеОшибкиПриУсовершенствовании();
		Ошибка.Текст = ОписаниеОшибки;
		УсовершенствоватьНаСторонеПослеОшибки(Ошибка, Контекст);
		Возврат;
	КонецЕсли;
	
	Контекст.ОперацияНачалась = Истина;
	Контекст.ЭлементДанных.Вставить("СвойстваПодписи", Новый Структура("Подпись", ДвоичныеДанные));

	Оповещение = Новый ОписаниеОповещения("ВыполнитьПослеПолученияКонтейнераУсовершенствованнойПодписи", ЭтотОбъект, Контекст, 
		"УсовершенствоватьНаСторонеЦиклПослеОшибкиОперацииНаКлиенте", ЭтотОбъект);
	Контекст.МенеджерКриптографии.НачатьПолучениеКонтейнераПодписейКриптографии(Оповещение, ДвоичныеДанные);

КонецПроцедуры

// Продолжение процедуры УсовершенствоватьНаСтороне.
Асинх Процедура ВыполнитьПослеПолученияКонтейнераУсовершенствованнойПодписи(КонтейнерПодписи, Контекст) Экспорт

	ДатаСеанса = ОбщегоНазначенияКлиент.ДатаСеанса();
	ДобавкаВремени = ДатаСеанса - ОбщегоНазначенияКлиент.ДатаУниверсальная();
	ПараметрыПодписи = Ждать ПараметрыПодписиКриптографии(
			КонтейнерПодписи, ДобавкаВремени, ДатаСеанса);
			
	Контекст.ЭлементДанных.Вставить("ПараметрыПодписи", ПараметрыПодписи);

	Если ПараметрыПодписи.СертификатПоследнейМеткиВремени <> Неопределено Тогда
		Оповещение = Новый ОписаниеОповещения("ВыполнитьНаСторонеПослеУсовершенствованияИПроверкиСертификата", ЭтотОбъект, Контекст); 
		ПроверитьСертификат(Оповещение, ПараметрыПодписи.СертификатПоследнейМеткиВремени, Контекст.МенеджерКриптографии);
	Иначе
		СвойстваПодписи = Новый Структура;
		СвойстваПодписи.Вставить("Подпись",             Контекст.ЭлементДанных.СвойстваПодписи.Подпись);
		СвойстваПодписи.Вставить("ТипПодписи",          ПараметрыПодписи.ТипПодписи);
		СвойстваПодписи.Вставить("СрокДействияПоследнейМеткиВремени", ПараметрыПодписи.СрокДействияПоследнейМеткиВремени);

		ВыполнитьНаСторонеЦиклПослеУсовершенствования(СвойстваПодписи, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры УсовершенствоватьНаСтороне.
Процедура ВыполнитьНаСторонеПослеУсовершенствованияИПроверкиСертификата(Результат, Контекст) Экспорт
	
	ПараметрыПодписи = Контекст.ЭлементДанных.ПараметрыПодписи;
	
	СвойстваПодписи = Новый Структура;
	СвойстваПодписи.Вставить("Подпись",             Контекст.ЭлементДанных.СвойстваПодписи.Подпись);
	СвойстваПодписи.Вставить("ТипПодписи",          ПараметрыПодписи.ТипПодписи);
	СвойстваПодписи.Вставить("СрокДействияПоследнейМеткиВремени", ПараметрыПодписи.СрокДействияПоследнейМеткиВремени);
	
	Если Результат = Истина Тогда
		ВыполнитьНаСторонеЦиклПослеУсовершенствования(СвойстваПодписи, Контекст);
	Иначе
		Ошибка = ОписаниеОшибкиПриУсовершенствовании();
		Ошибка.Текст = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru='При проверке сертификата подписи после усовершенствования: %1
			|%2'"), Результат, СвойстваСертификатаСтрокой(ПараметрыПодписи.СертификатПоследнейМеткиВремени));
		УсовершенствоватьНаСторонеПослеОшибки(Ошибка, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры УсовершенствоватьНаСтороне.
Процедура УсовершенствоватьНаСторонеЦиклПослеОшибкиОперацииНаКлиенте(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
	
	СтандартнаяОбработка = Ложь;
	
	Ошибка = ОписаниеОшибкиПриУсовершенствовании();
	Ошибка.Текст = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
	УсовершенствоватьНаСторонеПослеОшибки(Ошибка, Контекст);
	
КонецПроцедуры

// Продолжение процедуры УсовершенствоватьНаСтороне.
Процедура ВыполнитьНаСторонеЦиклПослеУсовершенствования(СвойстваПодписи, Контекст)

	ЭлементДанных = Контекст.ЭлементыДанных[Контекст.Индекс];
	
	Если Контекст.НаСторонеКлиента Тогда
		
		НовыеСвойстваПодписи = ЭлектроннаяПодписьКлиентСервер.НовыеСвойстваПодписи();
		ОбновитьПодпись = Ложь;
		
		Если Контекст.ЭлементДанных.Свойство("НеТребуетсяПродление") Тогда 
			Если ЭлементДанных.ТипПодписи <> СвойстваПодписи.ТипПодписи Тогда
				ЭлементДанных.ТипПодписи = СвойстваПодписи.ТипПодписи;
				НовыеСвойстваПодписи.ТипПодписи = СвойстваПодписи.ТипПодписи;
				ОбновитьПодпись = Истина;
			КонецЕсли;
			Если ЭлементДанных.СрокДействияПоследнейМеткиВремени <> СвойстваПодписи.СрокДействияПоследнейМеткиВремени Тогда
				ЭлементДанных.СрокДействияПоследнейМеткиВремени = СвойстваПодписи.СрокДействияПоследнейМеткиВремени;
				НовыеСвойстваПодписи.СрокДействияПоследнейМеткиВремени = СвойстваПодписи.СрокДействияПоследнейМеткиВремени;
				ОбновитьПодпись = Истина;
			КонецЕсли;
		Иначе
			НовыеСвойстваПодписи.Подпись = СвойстваПодписи.Подпись;
			НовыеСвойстваПодписи.ТипПодписи = СвойстваПодписи.ТипПодписи;
			НовыеСвойстваПодписи.СрокДействияПоследнейМеткиВремени = СвойстваПодписи.СрокДействияПоследнейМеткиВремени;
			ОбновитьПодпись = Истина;
		КонецЕсли;
		
		ЭлементДанных.Вставить("СвойстваПодписи", НовыеСвойстваПодписи);
		
		Если Не ЭлементДанных.Свойство("ПодписанныйОбъект") Тогда
			УсовершенствоватьНаСторонеЦиклНачало(Контекст);
			Возврат;
		КонецЕсли;
		
		Если ОбновитьПодпись Тогда
			ЭлементДанных.СвойстваПодписи.ПодписанныйОбъект = ЭлементДанных.ПодписанныйОбъект;
			ЭлементДанных.СвойстваПодписи.ПорядковыйНомер = ЭлементДанных.ПорядковыйНомер;
			
			ПредставлениеОшибки = ЭлектроннаяПодписьСлужебныйВызовСервера.ОбновитьУсовершенствованнуюПодпись(
				ЭлементДанных.СвойстваПодписи);
			
			Если ЗначениеЗаполнено(ПредставлениеОшибки) Тогда
				ЭлементДанных.Удалить("СвойстваПодписи");
				Ошибка = ОписаниеОшибкиПриУсовершенствовании();
				Ошибка.Текст = ПредставлениеОшибки;
				УсовершенствоватьНаСторонеПослеОшибки(Ошибка, Контекст);
				Возврат;
			КонецЕсли;
			
			Если ЗначениеЗаполнено(ЭлементДанных.СвойстваПодписи.Подпись) Тогда
				ЭлектроннаяПодписьСлужебныйВызовСервера.ЗарегистрироватьУсовершенствованиеПодписиВЖурнале(
					ЭлементДанных.СвойстваПодписи);
			КонецЕсли;
		КонецЕсли;
		
	Иначе

		ЭлементДанных.Вставить("СвойстваПодписи", СвойстваПодписи);
		
	КонецЕсли;

	ОповеститьОбИзменении(ЭлементДанных.ПодписанныйОбъект);
	УсовершенствоватьНаСторонеЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры УсовершенствоватьНаСтороне.
Процедура УсовершенствоватьНаСторонеПослеОшибки(Ошибка, Контекст)
	
	Контекст.ЕстьОшибки = Истина;
	
	ЭлементДанных = Контекст.ЭлементыДанных[Контекст.Индекс];
	Если Не ЭлементДанных.Свойство("Ошибка") Тогда
		ЭлементДанных.Вставить("Ошибка", "");
	КонецЕсли;
	
	ТекстОшибки = Ошибка.Текст;
	Если Не Контекст.ПрерыватьОбработкуМассиваПриОшибке Тогда
		
		Если Ошибка.ОшибкаСозданияМенеджераКриптографии Тогда
			ОшибкиСозданияМенеджераКриптографии = Контекст.ОшибкиСозданияМенеджераКриптографии;
			Если ОшибкиСозданияМенеджераКриптографии.Найти(ТекстОшибки) = Неопределено Тогда
				ОшибкиСозданияМенеджераКриптографии.Добавить(ТекстОшибки);
			КонецЕсли;
		КонецЕсли;
		
		ЭлементДанных.Ошибка = ЭлементДанных.Ошибка + ?(ЭлементДанных.Ошибка <> "", Символы.ПС, "")
		+ ?(Ошибка.НаКлиенте, НСтр("ru='На компьютере:'"), НСтр("ru='На сервере:'")) + " "
		+ Ошибка.Текст;
	Иначе
		ЭлементДанных.Ошибка = ЭлементДанных.Ошибка + ?(ЭлементДанных.Ошибка <> "", Символы.ПС, "")
			+ ?(Ошибка.НаКлиенте, НСтр("ru='На компьютере:'"), НСтр("ru='На сервере:'")) + " "
			+ Ошибка.Текст;
	КонецЕсли;
		
	Если Контекст.ПрерыватьОбработкуМассиваПриОшибке Тогда
		УсовершенствоватьНаСторонеПослеЦикла(Контекст, ТекстОшибки);
	Иначе
		УсовершенствоватьНаСторонеЦиклНачало(Контекст);
	КонецЕсли;
	
КонецПроцедуры 

// Для процедуры УсовершенствоватьНаСтороне.
Функция ОписаниеОшибкиПриУсовершенствовании(ОшибкаНаКлиенте = Истина)
	
	Возврат Новый Структура("НаКлиенте, Текст, ОшибкаСозданияМенеджераКриптографии",
		ОшибкаНаКлиенте, "", Ложь);
		
КонецФункции

// Продолжение процедуры УсовершенствоватьНаСтороне.
Процедура УсовершенствоватьНаСторонеПослеЦикла(Контекст, ТекстОшибки = Неопределено)
	
	Результат = Новый Структура;
	
	Если Контекст.ЕстьОшибки Или Не Контекст.ОперацияНачалась Тогда
		Результат.Вставить("Ошибка", Истина);
		Если Контекст.ЭлементыДанных.Количество() = 0 Тогда
			Результат.Вставить("ТекстОшибки", НСтр("ru='Нет подписей для обработки.'"));
		Иначе
			НетПодписейДляОбработки = Истина;
			Для Каждого ЭлементДанных Из Контекст.ЭлементыДанных Цикл
				Если Не ЭлементДанных.Свойство("НеТребуетсяПродление") Тогда
					НетПодписейДляОбработки = Ложь;
					Прервать;
				КонецЕсли;
			КонецЦикла;
			НачалоОшибки = ?(Контекст.НаСторонеКлиента, НСтр("ru='На компьютере:'"), НСтр("ru='На сервере:'"));
			Если Контекст.ОшибкиСозданияМенеджераКриптографии.Количество() > 0 Тогда
				Результат.Вставить("ТекстОшибки", НачалоОшибки + Символы.ПС + СтрСоединить(Контекст.ОшибкиСозданияМенеджераКриптографии, Символы.ПС));
			ИначеЕсли НетПодписейДляОбработки Тогда
				Результат.Вставить("ТекстОшибки", НСтр("ru='Нет подписей для обработки.'"));
			Иначе
				Результат.Вставить("ТекстОшибки", НачалоОшибки + Символы.ПС + НСтр("ru='Есть ошибки при продлении подписей'"));
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	Результат.Вставить("ЭлементыДанных", Контекст.ЭлементыДанных);
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
	
КонецПроцедуры

// Продолжение процедуры УсовершенствоватьНаСтороне.
Процедура УсовершенствоватьПослеВыполненияНаСторонеСервера(Результат, Контекст) Экспорт
	
	Если Результат <> Неопределено И Не Результат.Свойство("Ошибка") Тогда 
		УсовершенствоватьПослеВыполненияНаСторонеКлиента(Результат, Контекст);
	Иначе
		Если Результат <> Неопределено Тогда
			Контекст.ПараметрыВыполнения.Вставить("ЭлементыДанных", Результат.ЭлементыДанных);
			Контекст.ПараметрыВыполнения.Вставить("ТекстОшибки", Результат.ТекстОшибки);
		КонецЕсли;
		
		УсовершенствоватьНаСтороне(Новый ОписаниеОповещения(
				"УсовершенствоватьПослеВыполненияНаСторонеКлиента", ЭтотОбъект, Контекст),
			"НаСторонеКлиента", Контекст.ПараметрыВыполнения);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры УсовершенствоватьНаСтороне.
Процедура УсовершенствоватьПослеВыполненияНаСторонеКлиента(Результат, Контекст) Экспорт
	
	РезультатОбработки = Новый Структура("Успех, ТекстОшибки, СвойстваПодписей");
	
	Если Результат.Свойство("Ошибка") Тогда
		РезультатОбработки.Успех = Ложь;
		РезультатОбработки.ТекстОшибки = Результат.ТекстОшибки;
		
	Иначе
		РезультатОбработки.Успех = Истина;
	КонецЕсли;
	
	Если Контекст.ОбработкаРезультата = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Если Результат.Свойство("ЭлементыДанных") Тогда
		РезультатОбработки.СвойстваПодписей = Результат.ЭлементыДанных;
	КонецЕсли;
	
	ВыполнитьОбработкуОповещения(Контекст.ОбработкаРезультата, РезультатОбработки);
	
КонецПроцедуры

// Продолжение процедуры УсовершенствоватьНаСтороне.
Функция СвойстваСертификатаСтрокой(Сертификат)

	Если Сертификат = Неопределено Тогда
		Возврат "";
	КонецЕсли;
	
	СвойстваСертификата = ЭлектроннаяПодписьКлиент.СвойстваСертификата(Сертификат);
	СведенияОСертификате = 
		ЭлектроннаяПодписьСлужебныйКлиентСервер.СведенияОСертификатеСтрокой(СвойстваСертификата);
	
	Возврат СведенияОСертификате;
	
КонецФункции

#КонецОбласти
////////////////////////////////////////////////////////////////////////////////
// Работа с XMLDSig

// Начинает подписание XML сообщения.
//
// Параметры:
//  ОповещенияПриЗавершении - Структура:
//   * Успех  - ОписаниеОповещения - процедура, которая будет вызвана после подписания.
//   * Ошибка - ОписаниеОповещения - процедура, которая будет вызвана при ошибке подписания.
//  КонвертXML             - см. ЭлектроннаяПодписьКлиент.КонвертXML
//  ПараметрыXMLDSig       - см. ЭлектроннаяПодписьКлиент.ПараметрыXMLDSig
//  СертификатКриптографии - СертификатКриптографии
//  МенеджерКриптографии   - МенеджерКриптографии
//
Процедура НачатьВыгрузкуСертификатаКриптографииДляПодписанияXMLDSig(ОповещенияПриЗавершении, КонвертXML,
			ПараметрыXMLDSig, СертификатКриптографии, МенеджерКриптографии)
	
	СвойстваКонвертаXML = ЭлектроннаяПодписьСлужебныйВызовСервера.СвойстваКонвертаXML(КонвертXML,
		ПараметрыXMLDSig, Ложь);
	
	ДанныеАлгоритмаПодписания = Новый Структура(Новый ФиксированнаяСтруктура(ПараметрыXMLDSig));
	
	Контекст = Новый Структура;
	Контекст.Вставить("Режим",                   "РежимПодписание");
	Контекст.Вставить("ТипПодписи",              "XMLDSig");
	Контекст.Вставить("ОповещенияПриЗавершении", ОповещенияПриЗавершении);
	Контекст.Вставить("УстанавливатьКомпоненту", Истина);
	
	Контекст.Вставить("КонвертXML", КонвертXML);
	Контекст.Вставить("СвойстваКонвертаXML", СвойстваКонвертаXML);
	
	Контекст.Вставить("ДанныеАлгоритмаПодписания",    ДанныеАлгоритмаПодписания);
	Контекст.Вставить("СертификатКриптографии",       СертификатКриптографии);
	Контекст.Вставить("СертификатКриптографииBase64", Неопределено);
	Контекст.Вставить("МенеджерКриптографии",         МенеджерКриптографии);
	
	Контекст.Вставить("ТипКриптопровайдера", Неопределено);
	Контекст.Вставить("ИмяКриптопровайдера", Неопределено);
	Контекст.Вставить("ПутьКриптопровайдера", Неопределено);
	
	Если СвойстваКонвертаXML <> Неопределено
	   И ЗначениеЗаполнено(СвойстваКонвертаXML.ТекстОшибки) Тогда
		
		ЗавершитьОперациюСОшибкой(Контекст, СвойстваКонвертаXML.ТекстОшибки);
		Возврат;
	КонецЕсли;
	
	СертификатКриптографии.НачатьВыгрузку(
		Новый ОписаниеОповещения("НачатьПодписание_ПослеВыгрузкиСертификатаКриптографии", ЭтотОбъект, Контекст));
	
КонецПроцедуры

// Начинает проверку подписи XML сообщения.
//
// Параметры:
//  ОповещенияПриЗавершении - Структура:
//   * Успех  - ОписаниеОповещения - процедура, которая будет вызвана после проверки подписи.
//   * Ошибка - ОписаниеОповещения - процедура, которая будет вызвана при ошибке проверки подписи.
//  КонвертXML           - см. ЭлектроннаяПодписьКлиент.КонвертXML
//  ПараметрыXMLDSig     - см. ЭлектроннаяПодписьКлиент.ПараметрыXMLDSig
//  СвойстваКонвертаXML  - см. ЭлектроннаяПодписьСлужебный.СвойстваКонвертаXML
//  МенеджерКриптографии - МенеджерКриптографии
//
Процедура НачатьИнициализациюСертификатаКриптографииДляПроверкиПодписиXMLDSig(ОповещенияПриЗавершении, КонвертXML,
			ПараметрыXMLDSig, СвойстваКонвертаXML, МенеджерКриптографии)
	
	Если СвойстваКонвертаXML = Неопределено Тогда
		СертификатКриптографииBase64 = ЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатИзКонвертаSOAP(КонвертXML);
	Иначе
		СертификатКриптографииBase64 = СвойстваКонвертаXML.Сертификат.ЗначениеСертификата;
	КонецЕсли;
	ДвоичныеДанные = Base64Значение(СертификатКриптографииBase64);
	ДанныеАлгоритмаПодписания = Новый Структура(Новый ФиксированнаяСтруктура(ПараметрыXMLDSig));
	
	Контекст = Новый Структура;
	Контекст.Вставить("Режим",                   "РежимПроверка");
	Контекст.Вставить("ТипПодписи",              "XMLDSig");
	Контекст.Вставить("ОповещенияПриЗавершении", ОповещенияПриЗавершении);
	Контекст.Вставить("УстанавливатьКомпоненту", Истина);
	
	Контекст.Вставить("КонвертXML", КонвертXML);
	Контекст.Вставить("СвойстваКонвертаXML", СвойстваКонвертаXML);
	
	Контекст.Вставить("ДанныеАлгоритмаПодписания", ДанныеАлгоритмаПодписания);
	Контекст.Вставить("СертификатКриптографии",    Новый СертификатКриптографии);
	Контекст.Вставить("СертификатКриптографииBase64", СертификатКриптографииBase64);
	Контекст.Вставить("МенеджерКриптографии",      МенеджерКриптографии);
	
	Контекст.Вставить("ТипКриптопровайдера",  Неопределено);
	Контекст.Вставить("ИмяКриптопровайдера",  Неопределено);
	Контекст.Вставить("ПутьКриптопровайдера", Неопределено);
	
	Контекст.СертификатКриптографии.НачатьИнициализацию(Новый ОписаниеОповещения(
			"НачатьПроверкуПодписиПослеИнициализацииСертификата", ЭтотОбъект, Контекст),
		ДвоичныеДанные);
	
КонецПроцедуры

// Начинает подписание CMS сообщения.
Процедура НачатьВыгрузкуСертификатаКриптографииДляПодписанияCMS(ОповещенияПриЗавершении, Данные, ПараметрыCMS, СертификатКриптографии, МенеджерКриптографии)
	
	Контекст = Новый Структура;
	Контекст.Вставить("Режим",                   "РежимПодписание");
	Контекст.Вставить("ТипПодписи",              "CMS");
	Контекст.Вставить("ОповещенияПриЗавершении", ОповещенияПриЗавершении);
	Контекст.Вставить("УстанавливатьКомпоненту", Истина);
	
	Контекст.Вставить("Данные", Данные);
	
	Контекст.Вставить("ПараметрыCMS",                 ПараметрыCMS);
	Контекст.Вставить("СертификатКриптографии",       СертификатКриптографии);
	Контекст.Вставить("СертификатКриптографииBase64", Неопределено);
	Контекст.Вставить("МенеджерКриптографии",         МенеджерКриптографии);
	
	Контекст.Вставить("ТипКриптопровайдера", Неопределено);
	Контекст.Вставить("ИмяКриптопровайдера", Неопределено);
	Контекст.Вставить("ПутьКриптопровайдера", Неопределено);
	
	СертификатКриптографии.НачатьВыгрузку(
		Новый ОписаниеОповещения("НачатьПодписаниеCMS_ПослеВыгрузкиСертификатаКриптографии", ЭтотОбъект, Контекст));
	
КонецПроцедуры

// Начинает проверку подписи CMS сообщения.
Процедура НачатьИнициализациюСертификатаКриптографииДляПроверкиПодписиCMS(ОповещенияПриЗавершении, Подпись, Данные, ПараметрыCMS, МенеджерКриптографии)
	
	Контекст = Новый Структура;
	Контекст.Вставить("Режим",                   "РежимПроверка");
	Контекст.Вставить("ТипПодписи",              "CMS");
	Контекст.Вставить("ОповещенияПриЗавершении", ОповещенияПриЗавершении);
	Контекст.Вставить("УстанавливатьКомпоненту", Истина);
	
	Контекст.Вставить("Данные", Данные);
	Контекст.Вставить("Подпись", Подпись);
	Контекст.Вставить("ПараметрыCMS", ПараметрыCMS);
	
	Контекст.Вставить("СертификатКриптографии",    Неопределено);
	Контекст.Вставить("МенеджерКриптографии",      МенеджерКриптографии);
	
	Контекст.Вставить("ТипКриптопровайдера",  Неопределено);
	Контекст.Вставить("ИмяКриптопровайдера",  Неопределено);
	Контекст.Вставить("ПутьКриптопровайдера", Неопределено);
	
	НачатьПроверкуПодписиПослеИнициализацииСертификата(Неопределено, Контекст);
	
КонецПроцедуры

Процедура НачатьПроверкуПодписиПослеИнициализацииСертификата(СертификатКриптографии, Контекст) Экспорт
	
	Контекст.СертификатКриптографии = СертификатКриптографии;
	
	ТекстПояснения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Для проверки подписи %1 необходима установка компоненты %2'"),
		?(Контекст.ТипПодписи = "CMS", "CMS", "XML"), "ExtraCryptoAPI");
	
	ПодключитьКомпоненту(Контекст, ТекстПояснения);
	
КонецПроцедуры

Процедура ПодключитьКомпоненту(Контекст, ТекстПояснения)
	
	ПараметрыПодключения = ОбщегоНазначенияКлиент.ПараметрыПодключенияКомпоненты();
	ПараметрыПодключения.ТекстПояснения = ТекстПояснения;
	ПараметрыПодключения.ПредложитьЗагрузить = Истина;
	
	ОписаниеКомпоненты = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОписаниеКомпоненты();
	
	ОбщегоНазначенияКлиент.ПодключитьКомпонентуИзМакета(
		Новый ОписаниеОповещения("ПослеПодключенияКомпоненты", ЭтотОбъект, Контекст),
		ОписаниеКомпоненты.ИмяОбъекта,
		ОписаниеКомпоненты.ПолноеИмяМакета,
		ПараметрыПодключения);
	
КонецПроцедуры

Процедура ПослеПодключенияКомпоненты(Результат, Контекст) Экспорт
	
	Если Результат.Подключено Тогда
		Контекст.Вставить("ОбъектКомпоненты", Результат.ПодключаемыйМодуль);
		ПослеПодключенияКомпонентыНастроитьКомпоненту(Контекст);
	Иначе
		
		Если ПустаяСтрока(Результат.ОписаниеОшибки) Тогда 
			
			// Пользователь отказался от установки.
			
			ЗавершитьОперациюСОшибкой(
				Контекст,
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Операция невозможна. Требуется установка компоненты %1.'"), "ExtraCryptoAPI"));
				
		Иначе
			
			// Установка не удалась, описание ошибки в Результат.ОписаниеОшибки.
			
			ЗавершитьОперациюСОшибкой(
				Контекст,
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Операция невозможна. %1'"), Результат.ОписаниеОшибки));
			
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ПослеПодключенияКомпонентыНастроитьКомпоненту(Контекст)
	
	Оповещение = Новый ОписаниеОповещения(
		"ПослеПодключенияКомпонентыПослеУстановкиСоответствиеOID", ЭтотОбъект, Контекст,
		"ПослеПодключенияКомпонентыПослеОшибкиУстановкиСоответствиеOID", ЭтотОбъект);
	
	Контекст.ОбъектКомпоненты.НачатьУстановкуСоответствиеOID(Оповещение,
		ЭлектроннаяПодписьСлужебныйКлиентСервер.ИдентификаторыАлгоритмовХешированияИОткрытогоКлюча());
	
КонецПроцедуры

Процедура ПослеПодключенияКомпонентыПослеУстановкиСоответствиеOID(Контекст) Экспорт
	
	Контекст.МенеджерКриптографии.НачатьПолучениеИнформацииМодуляКриптографии(
		Новый ОписаниеОповещения("ПослеПолученияИнформацииМодуляКриптографии", ЭтотОбъект, Контекст));
	
КонецПроцедуры

Процедура ПослеПодключенияКомпонентыПослеОшибкиУстановкиСоответствиеOID(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
	
	СтандартнаяОбработка = Ложь;
	
	ЗавершитьОперациюСОшибкой(Контекст,
		СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось установить свойство %1 компоненты %2 по причине:
				|%3'"), "СоответствиеOID", "ExtraCryptoAPI", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)));
	
КонецПроцедуры

// Параметры:
//   ИнформацияМодуляКриптографии - ИнформацияМодуляКриптографии
//   Контекст - Структура
//
Асинх Процедура ПослеПолученияИнформацииМодуляКриптографии(ИнформацияМодуляКриптографии, Контекст) Экспорт
	
	ИмяКриптопровайдера = ИнформацияМодуляКриптографии.Имя;
	
	ОписаниеОшибки = "";
	
	КриптопровайдерыРезультат = Ждать УстановленныеКриптопровайдерыИзКэша();
	ПрограммыАвто = ЭлектроннаяПодписьСлужебныйКлиентСервер.РезультатПоискаКриптопровайдеров(КриптопровайдерыРезультат);
		
	Если ТипЗнч(ПрограммыАвто) = Тип("Строка") Тогда
		ОписаниеОшибки = ПрограммыАвто;
		ПрограммыАвто = Неопределено;
	КонецЕсли;
	
	ОписаниеПрограммы = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОписаниеПрограммыПоИмениКриптопровайдера(
		ИмяКриптопровайдера, ЭлектроннаяПодписьКлиент.ОбщиеНастройки().ОписанияПрограмм, ПрограммыАвто); // см. ЭлектроннаяПодписьСлужебныйПовтИсп.ОписаниеПрограммы
	
	Если ОписаниеПрограммы = Неопределено Тогда
		Если Не ПустаяСтрока(ОписаниеОшибки) Тогда
			ЗавершитьОперациюСОшибкой(Контекст, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось определить тип криптопровайдера %1. %2'"), ИнформацияМодуляКриптографии.Имя, ОписаниеОшибки));
		Иначе
			ЗавершитьОперациюСОшибкой(Контекст, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось определить тип криптопровайдера %1'"), ИнформацияМодуляКриптографии.Имя));
		КонецЕсли;
		Возврат;
	КонецЕсли;
	
	Контекст.ТипКриптопровайдера = ОписаниеПрограммы.ТипПрограммы;
	Контекст.ИмяКриптопровайдера = ИмяКриптопровайдера;
	
	Если ОписаниеПрограммы.Свойство("Автоопределение") Тогда
		ОписаниеПути = Новый Структура("ПутьКПрограмме, Существует", ОписаниеПрограммы.ПутьКПрограммеАвто, Истина);
		ПослеПолученияПутиКПрограмме(ОписаниеПути, Контекст);
		Возврат;
	КонецЕсли;
	
	ПолучитьПутьКПрограмме(Новый ОписаниеОповещения("ПослеПолученияПутиКПрограмме",
		ЭтотОбъект, Контекст), ОписаниеПрограммы.Ссылка);
	
КонецПроцедуры

Процедура ПослеПолученияПутиКПрограмме(ОписаниеПути, Контекст) Экспорт
	
	Контекст.ПутьКриптопровайдера = ОписаниеПути.ПутьКПрограмме;
	
	Оповещение = Новый ОписаниеОповещения(
		"ПослеУстановкиСвойстваКомпонентыПутьККриптопровайдеру", ЭтотОбъект, Контекст);
	
	Контекст.ОбъектКомпоненты.НачатьУстановкуПутьККриптопровайдеру(Оповещение,
		Контекст.ПутьКриптопровайдера);
	
КонецПроцедуры

Процедура ПослеУстановкиСвойстваКомпонентыПутьККриптопровайдеру(Контекст) Экспорт
	
	Если Не ТребуетсяПутьКПрограмме() Тогда
		Оповещение = Новый ОписаниеОповещения(
			"ПослеУстановкиСвойстваЗапретитьПользовательскийИнтерфейс", ЭтотОбъект, Контекст);
		
		Контекст.ОбъектКомпоненты.НачатьУстановкуЗапретитьПользовательскийИнтерфейс(Оповещение,
			Не ИспользуетсяИнтерактивныйРежимКриптографии(Контекст.МенеджерКриптографии));
	Иначе
		ПослеУстановкиСвойстваЗапретитьПользовательскийИнтерфейс(Контекст);
	КонецЕсли;
	
КонецПроцедуры

Процедура ПослеУстановкиСвойстваЗапретитьПользовательскийИнтерфейс(Контекст) Экспорт
	
	Если Контекст.ТипПодписи = "XMLDSig" Тогда
		
		Если Контекст.Режим = "РежимПроверка" Тогда
			НачатьПроверкуПодписиXMLDSig(Контекст);
			
		ИначеЕсли Контекст.Режим = "РежимПодписание" Тогда
			НачатьПодписаниеXMLDSig(Контекст);
		Иначе
			ЗавершитьОперациюСОшибкой(Контекст, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не установлен режим работы компоненты %1.'"), "ExtraCryptoAPI"));
		КонецЕсли;
		
	ИначеЕсли Контекст.ТипПодписи = "CMS" Тогда
		
		Если Контекст.Режим = "РежимПроверка" Тогда
			НачатьПроверкуПодписиCMS(Контекст);
			
		ИначеЕсли Контекст.Режим = "РежимПодписание" Тогда
			НачатьПодписаниеCMS(Контекст);
		Иначе
			ЗавершитьОперациюСОшибкой(Контекст, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не установлен режим работы компоненты %1.'"), "ExtraCryptoAPI"));
		КонецЕсли;
		
	Иначе
		
		ЗавершитьОперациюСОшибкой(Контекст, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не установлен тип подписи компоненты %1.'"), "ExtraCryptoAPI"));
	КонецЕсли;
	
КонецПроцедуры

Процедура НачатьПодписание_ПослеВыгрузкиСертификатаКриптографии(ДвоичныеДанныеСертификата, Контекст) Экспорт
	
	Контекст.СертификатКриптографииBase64 =
		ЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатКриптографииBase64(
			ДвоичныеДанныеСертификата);
	
	ПодключитьКомпоненту(Контекст, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Для подписания XML необходима установка компоненты %1'"), "ExtraCryptoAPI"));
	
КонецПроцедуры

Процедура НачатьПодписаниеCMS_ПослеВыгрузкиСертификатаКриптографии(ДвоичныеДанныеСертификата, Контекст) Экспорт
	
	Контекст.СертификатКриптографииBase64 =
		ЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатКриптографииBase64(
			ДвоичныеДанныеСертификата);
	
	ПодключитьКомпоненту(Контекст, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Для подписания CMS необходима установка компоненты %1'"), "ExtraCryptoAPI"));
		
	
КонецПроцедуры

Процедура НачатьПодписаниеCMS(Контекст)
	
	ПараметрыCMSSign = ЭлектроннаяПодписьСлужебныйКлиентСервер.ПараметрыКомпонентыCMSSign(
		Контекст.ПараметрыCMS, Контекст.Данные);
	
	Оповещение = Новый ОписаниеОповещения(
		"Подписание_ПослеВыполненияCMSSign", ЭтотОбъект, Контекст,
		"Подписание_ПослеВыполненияCMSSign_Ошибка", ЭтотОбъект);
	
	Попытка
		Контекст.ОбъектКомпоненты.НачатьВызовCMSSign(Оповещение,
			ПараметрыCMSSign.Данные,
			Контекст.СертификатКриптографииBase64,
			Контекст.МенеджерКриптографии.ПарольДоступаКЗакрытомуКлючу,
			ПараметрыCMSSign.ТипПодписи,
			ПараметрыCMSSign.Открепленная,
			ПараметрыCMSSign.ВключениеСертификатовВПодпись);
	Исключение
		ЗавершитьОперациюСОшибкой(Контекст, ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("CMSSign",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())));
	КонецПопытки;
	
КонецПроцедуры

Процедура Подписание_ПослеВыполненияCMSSign_Ошибка(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
	
	СтандартнаяОбработка = Ложь;
	
	ЗавершитьОперациюСОшибкой(Контекст, ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("CMSSign",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)));
	
КонецПроцедуры

Процедура Подписание_ПослеВыполненияCMSSign(АтрибутSignatureValue, Параметры, Контекст) Экспорт
	
	Если Не ЗначениеЗаполнено(АтрибутSignatureValue) Тогда
		НачатьПолучениеТекстаОшибки(НачалоОписанияТекстаОшибки("CMSSign"), Контекст);
		Возврат;
	КонецЕсли;
	
	ВыполнитьОбработкуОповещения(Контекст.ОповещенияПриЗавершении.Успех, АтрибутSignatureValue);
	
КонецПроцедуры

Процедура НачатьПроверкуПодписиCMS(Контекст)
	
	ПараметрыCMSSign = ЭлектроннаяПодписьСлужебныйКлиентСервер.ПараметрыКомпонентыCMSSign(
		Контекст.ПараметрыCMS, Контекст.Данные);
	
	Оповещение = Новый ОписаниеОповещения(
		"Проверка_ПослеВыполненияCMSVerifySign", ЭтотОбъект, Контекст,
		"Проверка_ПослеВыполненияCMSVerifySign_Ошибка", ЭтотОбъект);
	
	Попытка
		Контекст.ОбъектКомпоненты.НачатьВызовCMSVerifySign(Оповещение,
			Контекст.Подпись,
			ПараметрыCMSSign.Открепленная,
			Контекст.Данные,
			Контекст.ТипКриптопровайдера,
			Null);
	Исключение
		ЗавершитьОперациюСОшибкой(Контекст, 
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("CMSVerifySign",
				ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())));
				
	КонецПопытки;
	
КонецПроцедуры

Процедура Проверка_ПослеВыполненияCMSVerifySign_Ошибка(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
	
	СтандартнаяОбработка = Ложь;
	
	ЗавершитьОперациюСОшибкой(Контекст,
		ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("CMSVerifySign",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)));
	
КонецПроцедуры

Процедура Проверка_ПослеВыполненияCMSVerifySign(ПодписьВерна, Параметры, Контекст) Экспорт
	
	Если ПодписьВерна <> Истина Тогда
		НачатьПолучениеТекстаОшибки(НачалоОписанияТекстаОшибки("CMSVerifySign"), Контекст);
		Возврат;
	КонецЕсли;
	
	Если ТипЗнч(Параметры[4]) = Тип("ДвоичныеДанные") Тогда
		Контекст.СертификатКриптографии = Параметры[4];
	Иначе
		ЗавершитьОперациюСОшибкой(Контекст,
			НСтр("ru = 'Подпись верна, но не содержит данных сертификата.'"));
		Возврат;
	КонецЕсли;
	
	ЭлектроннаяПодписьКлиент.ДатаПодписания(
		Новый ОписаниеОповещения("Проверка_ПослеВыполненияHash_ПодписываемыйТегПослеПолученияДатыПодписания", ЭтотОбъект, Контекст), Контекст.Подпись);
	
КонецПроцедуры

Асинх Процедура НачатьПодписаниеXMLDSig(Контекст)
	
	Попытка
		КонвертXML = Ждать ПодписатьXMLDSig(Контекст);
		ВыполнитьОбработкуОповещения(Контекст.ОповещенияПриЗавершении.Успех, КонвертXML);
	Исключение
		ТекстОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
		ЗавершитьОперациюСОшибкой(Контекст, ТекстОшибки);
	КонецПопытки;

КонецПроцедуры

Асинх Функция ПодписатьXMLDSig(Контекст)
	
	Пароль = Контекст.МенеджерКриптографии.ПарольДоступаКЗакрытомуКлючу;
	ОбъектКомпоненты = Контекст.ОбъектКомпоненты;
	КонвертXML = Контекст.КонвертXML;
	СвойстваКонвертаXML = Контекст.СвойстваКонвертаXML;
	
	Если СвойстваКонвертаXML <> Неопределено
	   И ЗначениеЗаполнено(СвойстваКонвертаXML.ТекстОшибки) Тогда
		ВызватьИсключение СвойстваКонвертаXML.ТекстОшибки;
	КонецЕсли;
	
	СертификатКриптографииBase64 = Контекст.СертификатКриптографииBase64;
	
	ДанныеАлгоритмаПодписания = Контекст.ДанныеАлгоритмаПодписания;
	ЭлектроннаяПодписьСлужебныйКлиентСервер.ПроверитьВыбратьАлгоритмПодписи(
		СертификатКриптографииBase64, ДанныеАлгоритмаПодписания, Истина, СвойстваКонвертаXML);
	
	КонвертXML = СтрЗаменить(КонвертXML, "%BinarySecurityToken%", СертификатКриптографииBase64);
	КонвертXML = СтрЗаменить(КонвертXML, "%SignatureMethod%", ДанныеАлгоритмаПодписания.ВыбранныйАлгоритмПодписи);
	КонвертXML = СтрЗаменить(КонвертXML, "%DigestMethod%",    ДанныеАлгоритмаПодписания.ВыбранныйАлгоритмХеширования);
	
	Если СвойстваКонвертаXML <> Неопределено Тогда
		Для Индекс = 0 По СвойстваКонвертаXML.ХешируемыеОбласти.ВГраница() Цикл
			ХешируемаяОбласть = СвойстваКонвертаXML.ХешируемыеОбласти[Индекс];
			КанонизированныйТекстXMLBody = Ждать КанонизированныйТекстXML(ОбъектКомпоненты,
					СвойстваКонвертаXML.ОбластиBody[Индекс], ХешируемаяОбласть.АлгоритмыТрансформации);
			АтрибутDigestValue = Ждать РезультатHash(ОбъектКомпоненты,
					КанонизированныйТекстXMLBody,
					ДанныеАлгоритмаПодписания.OIDВыбранногоАлгоритмаХеширования,
					Контекст.ТипКриптопровайдера);

			КонвертXML = СтрЗаменить(КонвертXML, ХешируемаяОбласть.ЗначениеХеша, АтрибутDigestValue);
		КонецЦикла;
	Иначе
		КанонизированныйТекстXMLBody = Ждать C14NАсинх(ОбъектКомпоненты,
		КонвертXML, ДанныеАлгоритмаПодписания.XPathПодписываемыйТег);
		
		АтрибутDigestValue = Ждать РезультатHash(ОбъектКомпоненты,
				КанонизированныйТекстXMLBody,
				ДанныеАлгоритмаПодписания.OIDВыбранногоАлгоритмаХеширования,
				Контекст.ТипКриптопровайдера);

		КонвертXML = СтрЗаменить(КонвертXML, "%DigestValue%", АтрибутDigestValue);
	КонецЕсли;
	
	Если СвойстваКонвертаXML = Неопределено Тогда
		КанонизированныйТекстXMLSignedInfo = Ждать C14NАсинх(ОбъектКомпоненты,
			КонвертXML, ДанныеАлгоритмаПодписания.XPathSignedInfo);
	Иначе
		ОбластьSignedInfo = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОбластьXML(КонвертXML,
			СвойстваКонвертаXML.ОбластьSignedInfo.ИмяЭлемента);
		ОбластьSignedInfo.ПространстваИменДоУзла =
			СвойстваКонвертаXML.ОбластьSignedInfo.ПространстваИменДоУзла;
		
		Если ЗначениеЗаполнено(ОбластьSignedInfo.ТекстОшибки) Тогда
			ВызватьИсключение ОбластьSignedInfo.ТекстОшибки;
		КонецЕсли;
		
		КанонизированныйТекстXMLSignedInfo = Ждать КанонизированныйТекстXML(ОбъектКомпоненты,
			ОбластьSignedInfo,
			ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(СвойстваКонвертаXML.АлгоритмКанонизации));
	КонецЕсли;
	
	АтрибутSignatureValue = Ждать РезультатSign(ОбъектКомпоненты,
		КанонизированныйТекстXMLSignedInfo,
		Контекст.СертификатКриптографии,
		Пароль);
	
	КонвертXML = СтрЗаменить(КонвертXML, "%SignatureValue%", АтрибутSignatureValue);
	
	Возврат КонвертXML;
	
КонецФункции

Асинх Функция РезультатHash(ОбъектКомпоненты, КанонизированныйТекстXMLBody, OIDАлгоритмаХеширования, ТипКриптопровайдера)
	
	Попытка
		Результат = Ждать ОбъектКомпоненты.HashАсинх(
			КанонизированныйТекстXMLBody,
			OIDАлгоритмаХеширования,
			ТипКриптопровайдера);
		АтрибутDigestValue = Результат.Значение;
	Исключение
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("Hash",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;
	
	Если АтрибутDigestValue = Неопределено Тогда
		РезультатОшибка = Ждать ОбъектКомпоненты.ПолучитьОшибкуАсинх();
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("Hash",
			РезультатОшибка.Значение);
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	Возврат АтрибутDigestValue;
	
КонецФункции

Асинх Функция РезультатSign(ОбъектКомпоненты, КанонизированныйТекстXMLSignedInfo,
	СертификатКриптографии, ПарольДоступаКЗакрытомуКлючу)
	
	СертификатКриптографииBase64 = Ждать СертификатКриптографии.ВыгрузитьАсинх();
	
	СертификатКриптографииBase64 = ЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатКриптографииBase64(
		СертификатКриптографииBase64);

	Попытка
		Результат = Ждать ОбъектКомпоненты.SignАсинх(
			КанонизированныйТекстXMLSignedInfo,
			СертификатКриптографииBase64,
			ПарольДоступаКЗакрытомуКлючу);
		АтрибутSignatureValue = Результат.Значение;
	Исключение
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("Sign",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;
	
	Если АтрибутSignatureValue = Неопределено Тогда
		РезультатОшибка = Ждать ОбъектКомпоненты.ПолучитьОшибкуАсинх();
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("Sign",
			РезультатОшибка.Значение);
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	Возврат АтрибутSignatureValue;
	
КонецФункции

Асинх Процедура НачатьПроверкуПодписиXMLDSig(Контекст)
	
	ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ПроверитьВыбратьАлгоритмПодписи(
		Контекст.СертификатКриптографииBase64, Контекст.ДанныеАлгоритмаПодписания, , Контекст.СвойстваКонвертаXML);
	
	Если ЗначениеЗаполнено(ТекстОшибки) Тогда
		ЗавершитьОперациюСОшибкой(Контекст, ТекстОшибки);
		Возврат;
	КонецЕсли;
	
	Попытка
		Результат = Ждать ПроверитьПодписьXMLDSig(Контекст);
		ВыполнитьОбработкуОповещения(Контекст.ОповещенияПриЗавершении.Успех, Результат);
	Исключение
		ТекстОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
		ЗавершитьОперациюСОшибкой(Контекст, ТекстОшибки);
	КонецПопытки;
	
КонецПроцедуры

Асинх Функция ПроверитьПодписьXMLDSig(Контекст)
	
	ОбъектКомпоненты = Контекст.ОбъектКомпоненты;
	ДанныеАлгоритмаПодписания = Контекст.ДанныеАлгоритмаПодписания;
	КонвертXML = Контекст.КонвертXML;
	СвойстваКонвертаXML = Контекст.СвойстваКонвертаXML;
		
	Если СвойстваКонвертаXML = Неопределено Тогда
		КанонизированныйТекстXMLSignedInfo = Ждать C14NАсинх(ОбъектКомпоненты,
			КонвертXML, ДанныеАлгоритмаПодписания.XPathSignedInfo);
		КанонизированныйТекстXMLBody = Ждать C14NАсинх(ОбъектКомпоненты,
			КонвертXML, ДанныеАлгоритмаПодписания.XPathПодписываемыйТег);
		СертификатКриптографииBase64 = ЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатИзКонвертаSOAP(КонвертXML);
		ЗначениеПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.НайтиВXML(КонвертXML, "SignatureValue");
		ЗначениеХеша    = ЭлектроннаяПодписьСлужебныйКлиентСервер.НайтиВXML(КонвертXML, "DigestValue");
	Иначе
		КанонизированныйТекстXMLSignedInfo = Ждать КанонизированныйТекстXML(ОбъектКомпоненты,
			СвойстваКонвертаXML.ОбластьSignedInfo,
			ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(СвойстваКонвертаXML.АлгоритмКанонизации));
		
		ЗначениеПодписи = СвойстваКонвертаXML.ЗначениеПодписи;
		СертификатКриптографииBase64 = СвойстваКонвертаXML.Сертификат.ЗначениеСертификата;
		ЭлектроннаяПодписьСлужебныйКлиентСервер.ПроверитьВыбратьАлгоритмПодписи(
			СертификатКриптографииBase64, ДанныеАлгоритмаПодписания, Истина, СвойстваКонвертаXML);
	КонецЕсли;
	
	ПодписьВерна = Ждать РезультатVerifySign(ОбъектКомпоненты,
		КанонизированныйТекстXMLSignedInfo,
		ЗначениеПодписи,
		СертификатКриптографииBase64,
		Контекст.ТипКриптопровайдера);
	
	Если СвойстваКонвертаXML <> Неопределено Тогда
		
		Счетчик = 1;
		
		Для Каждого ХешируемаяОбласть Из СвойстваКонвертаXML.ХешируемыеОбласти Цикл
			КанонизированныйТекстXMLBody = Ждать КанонизированныйТекстXML(ОбъектКомпоненты,
				СвойстваКонвертаXML.ОбластиBody[Счетчик-1], ХешируемаяОбласть.АлгоритмыТрансформации);
			ЗначениеХеша = ХешируемаяОбласть.ЗначениеХеша; 
			
			АтрибутDigestValue = Ждать РезультатHash(ОбъектКомпоненты,
				КанонизированныйТекстXMLBody,
				ДанныеАлгоритмаПодписания.OIDВыбранногоАлгоритмаХеширования,
				Контекст.ТипКриптопровайдера);
				
			ХешСовпадает = (АтрибутDigestValue = ЗначениеХеша);
			
			Если Не ХешСовпадает Или Не ПодписьВерна Тогда
				ВызватьИсключение ЭлектроннаяПодписьСлужебныйКлиентСервер.ТекстОшибкиПроверкиПодписиXML(ПодписьВерна, ХешСовпадает);
			КонецЕсли;
			Счетчик = Счетчик + 1;
		КонецЦикла;
		
		Возврат Ждать РезультатПроверкиПодписиXML(СертификатКриптографииBase64);
	КонецЕсли;
	
	АтрибутDigestValue = Ждать РезультатHash(ОбъектКомпоненты,
		КанонизированныйТекстXMLBody,
		ДанныеАлгоритмаПодписания.OIDВыбранногоАлгоритмаХеширования,
		Контекст.ТипКриптопровайдера);
	
	ХешСовпадает = (АтрибутDigestValue = ЗначениеХеша);
	
	Если ХешСовпадает И ПодписьВерна Тогда
		Возврат Ждать РезультатПроверкиПодписиXML(СертификатКриптографииBase64);
	Иначе
		ВызватьИсключение ЭлектроннаяПодписьСлужебныйКлиентСервер.ТекстОшибкиПроверкиПодписиXML(ПодписьВерна, ХешСовпадает);
	КонецЕсли;

КонецФункции

Асинх Функция РезультатПроверкиПодписиXML(СертификатКриптографииBase64)
	
	ДвоичныеДанные = Base64Значение(СертификатКриптографииBase64);
	
	СертификатКриптографии = Новый СертификатКриптографии;
	Ждать СертификатКриптографии.ИнициализироватьАсинх(ДвоичныеДанные);

	Результат = Новый Структура;
	Результат.Вставить("Сертификат", СертификатКриптографии);
	Результат.Вставить("ДатаПодписания", Неопределено);

	Возврат Результат;
		
КонецФункции

Асинх Функция РезультатVerifySign(ОбъектКомпоненты, КанонизированныйТекстXMLSignedInfo,
	АтрибутSignatureValue, СертификатКриптографииBase64, ТипКриптопровайдера)
	
	Попытка
		Результат = Ждать ОбъектКомпоненты.VerifySignАсинх(
			КанонизированныйТекстXMLSignedInfo,
			АтрибутSignatureValue,
			СертификатКриптографииBase64,
			ТипКриптопровайдера);
		ПодписьВерна = Результат.Значение;
	Исключение
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("VerifySign",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;
	
	Если ПодписьВерна = Неопределено Тогда
		РезультатОшибка = Ждать ОбъектКомпоненты.ПолучитьОшибкуАсинх();
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("VerifySign",
			РезультатОшибка.Значение);
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	Возврат ПодписьВерна;
	
КонецФункции

Процедура Проверка_ПослеВыполненияHash_ПодписываемыйТегПослеПолученияДатыПодписания(ДатаПодписания, Контекст) Экспорт
	
	Если Не ЗначениеЗаполнено(ДатаПодписания) Тогда
		ДатаПодписания = Неопределено;
	КонецЕсли;
	
	ВозвращаемоеЗначение = Новый Структура;
	ВозвращаемоеЗначение.Вставить("Сертификат", Контекст.СертификатКриптографии);
	ВозвращаемоеЗначение.Вставить("ДатаПодписания", ДатаПодписания);
	
	ВыполнитьОбработкуОповещения(Контекст.ОповещенияПриЗавершении.Успех, ВозвращаемоеЗначение);
	
КонецПроцедуры

Асинх Функция C14NАсинх(ОбъектКомпоненты, КонвертXML, XPath)
	
	Попытка
		Результат = Ждать ОбъектКомпоненты.C14NАсинх(КонвертXML, XPath);
		КанонизированныйТекстXML = Результат.Значение;
	Исключение
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("C14N",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;
	
	Если КанонизированныйТекстXML = Неопределено Тогда
		
		РезультатОшибка = Ждать ОбъектКомпоненты.ПолучитьОшибкуАсинх();
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("C14N",
			РезультатОшибка.Значение);
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	Возврат КанонизированныйТекстXML;
	
КонецФункции

Асинх Функция КанонизированныйТекстXML(ОбъектКомпоненты, ОбластьXML, Алгоритмы)
	
	Результат = Неопределено;
	ВышестоящиеПространстваИменДобавлены = Ложь;
	
	Для Каждого Алгоритм Из Алгоритмы Цикл
		Если Алгоритм.Вид = "envsig" Тогда
			Продолжить;
		ИначеЕсли Алгоритм.Вид = "c14n"
		      Или Алгоритм.Вид = "smev" Тогда
			
			Если Не ВышестоящиеПространстваИменДобавлены Тогда
				ОписаниеНачалаОбласти = ЭлектроннаяПодписьСлужебныйКлиентСервер.РасширенноеНачалоОбластиXML(
					ОбластьXML, Алгоритм, Результат);
				Если ЗначениеЗаполнено(ОписаниеНачалаОбласти.ТекстОшибки) Тогда
					ВызватьИсключение ОписаниеНачалаОбласти.ТекстОшибки;
				КонецЕсли;
				ТекстXML = ЭлектроннаяПодписьСлужебныйКлиентСервер.ТекстОбластиXML(ОбластьXML,
					ОписаниеНачалаОбласти.Начало);
				ВышестоящиеПространстваИменДобавлены = Истина;
				
			ИначеЕсли Результат = Неопределено Тогда
				ТекстXML = ЭлектроннаяПодписьСлужебныйКлиентСервер.ТекстОбластиXML(ОбластьXML);
			Иначе
				ТекстXML = Результат;
			КонецЕсли;
			
			Если Алгоритм.Вид = "c14n" Тогда
				Результат = Ждать C14N_body(ОбъектКомпоненты, ТекстXML, Алгоритм);
			Иначе
				Результат = Ждать КанонизацияСМЭВ(ОбъектКомпоненты, ТекстXML);
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Если Результат = Неопределено Тогда
		Результат = ЭлектроннаяПодписьСлужебныйКлиентСервер.ТекстОбластиXML(ОбластьXML);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Асинх Функция C14N_body(ОбъектКомпоненты, ТекстXML, Алгоритм)
	
	Попытка
		Результат = Ждать ОбъектКомпоненты.c14n_bodyАсинх(ТекстXML,
			Алгоритм.Версия, Алгоритм.СКомментариями);
		КанонизированныйТекстXML = Результат.Значение;

	Исключение
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("C14N_body",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;
	
	Если КанонизированныйТекстXML = Неопределено Тогда
		РезультатОшибка = Ждать ОбъектКомпоненты.ПолучитьОшибкуАсинх();
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("C14N_body",
			РезультатОшибка.Значение);
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	Возврат КанонизированныйТекстXML;
	
КонецФункции

Асинх Функция КанонизацияСМЭВ(ОбъектКомпоненты, ТекстXML)
	
	Попытка
		Результат = Ждать ОбъектКомпоненты.TransformSMEVАсинх(ТекстXML);
		КанонизированныйТекстXML = Результат.Значение;
	Исключение
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("TransformSMEV",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;
	
	Если КанонизированныйТекстXML = Неопределено Тогда
		РезультатОшибка = Ждать ОбъектКомпоненты.ПолучитьОшибкуАсинх();
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("TransformSMEV",
			РезультатОшибка.Значение);
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	Возврат КанонизированныйТекстXML;
	
КонецФункции

Процедура НачатьПолучениеТекстаОшибки(НачалоОписанияТекстаОшибки, Контекст)
	
	Контекст.Вставить("НачалоОписанияТекстаОшибки", НачалоОписанияТекстаОшибки);
	
	Оповещение = Новый ОписаниеОповещения(
		"ПослеВыполненияПолучитьОшибку", ЭтотОбъект, Контекст,
		"ПослеВыполненияПолучитьОшибку_Ошибка", ЭтотОбъект);
	
	Попытка
		Контекст.ОбъектКомпоненты.НачатьВызовПолучитьОшибку(Оповещение);
	Исключение
		ЗавершитьОперациюСОшибкой(Контекст,
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("ПолучитьОшибку",
				ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())));
	КонецПопытки;
	
КонецПроцедуры

Процедура ПослеВыполненияПолучитьОшибку_Ошибка(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
	
	СтандартнаяОбработка = Ложь;
	
	ЗавершитьОперациюСОшибкой(Контекст,
		ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("ПолучитьОшибку",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)));
	
КонецПроцедуры

Процедура ПослеВыполненияПолучитьОшибку(ТекстОшибки, Параметры, Контекст) Экспорт
	
	ЗавершитьОперациюСОшибкой(Контекст,
		Контекст.НачалоОписанияТекстаОшибки + Символы.ПС + ТекстОшибки);
	
КонецПроцедуры

Процедура ЗавершитьОперациюСОшибкой(Контекст, ТекстОшибки)
	
	ВыполнитьОбработкуОповещения(Контекст.ОповещенияПриЗавершении.Ошибка, ТекстОшибки);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Вспомогательные процедуры и функции.

// Для процедур УстановитьПарольСертификата, ОткрытьНовуюФорму, ВыборСертификатаДляПодписанияИлиРасшифровки,
// ПроверитьСертификатСправочника.
//
Функция ФормаПередачаПараметров()
	
	ИмяПараметра = "СтандартныеПодсистемы.ПараметрыЭлектроннойПодписиИШифрования";
	Если ПараметрыПриложения[ИмяПараметра] = Неопределено Тогда
		ПараметрыПриложения.Вставить(ИмяПараметра, Новый Соответствие);
	КонецЕсли;
	
	Форма = ПараметрыПриложения["СтандартныеПодсистемы.ПараметрыЭлектроннойПодписиИШифрования"].Получить("ФормаПередачаПараметров");
	
	Если Форма = Неопределено Тогда
		Форма = ОткрытьФорму("Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования.Форма.ПередачаПараметров");
		ПараметрыПриложения["СтандартныеПодсистемы.ПараметрыЭлектроннойПодписиИШифрования"].Вставить("ФормаПередачаПараметров", Форма);
	КонецЕсли;
	
	Возврат Форма;
	
КонецФункции

// Для процедуры ОбработатьПарольВФорме.
Процедура ОбработатьПароль(ВнутренниеДанные, РеквизитПароль, СвойстваПароля,
			РеквизитЗапомнитьПароль, ДополнительныеПараметры, НовыйПароль = Null)
	
	Сертификат = ДополнительныеПараметры.Сертификат;
	
	ХранилищеПаролей = ВнутренниеДанные.Получить("ХранилищеПаролей");
	Если ХранилищеПаролей = Неопределено Тогда
		ХранилищеПаролей = Новый Соответствие;
		ВнутренниеДанные.Вставить("ХранилищеПаролей", ХранилищеПаролей);
	КонецЕсли;
	
	УстановленныеПароли = ВнутренниеДанные.Получить("УстановленныеПароли");
	Если УстановленныеПароли = Неопределено Тогда
		УстановленныеПароли = Новый Соответствие;
		ВнутренниеДанные.Вставить("УстановленныеПароли", УстановленныеПароли);
		ВнутренниеДанные.Вставить("ПоясненияУстановленныхПаролей", Новый Соответствие);
	КонецЕсли;
	
	УстановленныйПароль = УстановленныеПароли.Получить(Сертификат);
	ДополнительныеПараметры.Вставить("ПарольУстановленПрограммно", УстановленныйПароль <> Неопределено);
	Если УстановленныйПароль <> Неопределено Тогда
		ДополнительныеПараметры.Вставить("ПояснениеПароля",
			ВнутренниеДанные.Получить("ПоясненияУстановленныхПаролей").Получить(Сертификат));
	КонецЕсли;
	
	Если ДополнительныеПараметры.ВводитьПарольВПрограммеЭлектроннойПодписи Тогда
		СвойстваПароля.Значение = "";
		СвойстваПароля.ПарольПроверен = Ложь;
		РеквизитПароль = "";
		Значение = ХранилищеПаролей.Получить(Сертификат);
		Если Значение <> Неопределено Тогда
			ХранилищеПаролей.Удалить(Сертификат);
			Значение = Неопределено;
		КонецЕсли;
		ДополнительныеПараметры.Вставить("ПарольВПамяти", Ложь);
		
		Возврат;
	КонецЕсли;
	
	Пароль = ХранилищеПаролей.Получить(Сертификат);
	ДополнительныеПараметры.Вставить("ПарольВПамяти", Пароль <> Неопределено);
	
	Если ДополнительныеПараметры.ПриУстановкеПароляИзДругойОперации Тогда
		РеквизитПароль = ?(СвойстваПароля.Значение <> "", "****************", "");
		РеквизитЗапомнитьПароль = ДополнительныеПараметры.ПарольВПамяти;
		Возврат;
	КонецЕсли;
	
	Если ДополнительныеПараметры.ПриИзмененииРеквизитаПароль Тогда
		Если РеквизитПароль = "****************" Тогда
			Возврат;
		КонецЕсли;
		СвойстваПароля.Значение = РеквизитПароль;
		СвойстваПароля.ПарольПроверен = Ложь;
		РеквизитПароль = ?(СвойстваПароля.Значение <> "", "****************", "");
		
		Возврат;
	КонецЕсли;
	
	Если ДополнительныеПараметры.ПриИзмененииРеквизитаЗапомнитьПароль Тогда
		Если Не РеквизитЗапомнитьПароль Тогда
			Значение = ХранилищеПаролей.Получить(Сертификат);
			Если Значение <> Неопределено Тогда
				ХранилищеПаролей.Удалить(Сертификат);
				Значение = Неопределено;
			КонецЕсли;
			ДополнительныеПараметры.Вставить("ПарольВПамяти", Ложь);
			
		ИначеЕсли СвойстваПароля.ПарольПроверен Тогда
			ХранилищеПаролей.Вставить(Сертификат, СвойстваПароля.Значение);
			ДополнительныеПараметры.Вставить("ПарольВПамяти", Истина);
		КонецЕсли;
		
		Возврат;
	КонецЕсли;
	
	Если ДополнительныеПараметры.ПриУспешномВыполненииОперации Тогда
		Если РеквизитЗапомнитьПароль
		   И НЕ ДополнительныеПараметры.ПарольУстановленПрограммно Тогда
			
			ХранилищеПаролей.Вставить(Сертификат, СвойстваПароля.Значение);
			ДополнительныеПараметры.Вставить("ПарольВПамяти", Истина);
			СвойстваПароля.ПарольПроверен = Истина;
		КонецЕсли;
		
		Возврат;
	КонецЕсли;
	
	Если ДополнительныеПараметры.ПарольУстановленПрограммно Тогда
		Если НовыйПароль <> Null Тогда
			СвойстваПароля.Значение = Строка(НовыйПароль);
		Иначе
			СвойстваПароля.Значение = Строка(УстановленныйПароль);
		КонецЕсли;
		СвойстваПароля.ПарольПроверен = Ложь;
		РеквизитПароль = ?(СвойстваПароля.Значение <> "", "****************", "");
		
		Возврат;
	КонецЕсли;
	
	Если НовыйПароль <> Null Тогда
		// Установка нового пароля к новому сертификату.
		Если НовыйПароль <> Неопределено Тогда
			СвойстваПароля.Значение = Строка(НовыйПароль);
			СвойстваПароля.ПарольПроверен = Истина;
			НовыйПароль = "";
			Если ХранилищеПаролей.Получить(Сертификат) <> Неопределено Или РеквизитЗапомнитьПароль Тогда
				ХранилищеПаролей.Вставить(Сертификат, СвойстваПароля.Значение);
				ДополнительныеПараметры.Вставить("ПарольВПамяти", Истина);
			КонецЕсли;
		ИначеЕсли ХранилищеПаролей.Получить(Сертификат) <> Неопределено Тогда
			// Удаление сохраненного пароля из хранилища.
			РеквизитЗапомнитьПароль = Ложь;
			ХранилищеПаролей.Удалить(Сертификат);
			ДополнительныеПараметры.Вставить("ПарольВПамяти", Ложь);
		КонецЕсли;
		РеквизитПароль = ?(СвойстваПароля.Значение <> "", "****************", "");
		
		Возврат;
	КонецЕсли;
	
	Если ДополнительныеПараметры.ПриИзмененииСвойствСертификата Тогда
		Возврат;
	КонецЕсли;
	
	// Получение пароля из хранилища.
	Значение = ХранилищеПаролей.Получить(Сертификат);
	ДополнительныеПараметры.Вставить("ПарольВПамяти", Значение <> Неопределено);
	РеквизитЗапомнитьПароль = ДополнительныеПараметры.ПарольВПамяти;
	СвойстваПароля.Значение = Строка(Значение);
	СвойстваПароля.ПарольПроверен = ДополнительныеПараметры.ПарольВПамяти;
	Значение = Неопределено;
	РеквизитПароль = ?(СвойстваПароля.Значение <> "", "****************", "");
	
КонецПроцедуры

// Для процедуры НастроитьПредставлениеДанных.
Процедура ЗаполнитьСписокПредставлений(СписокПредставлений, ЭлементДанных)
	
	ЭлементСписка = Новый Структура("Значение, Представление", Неопределено, "");
	СписокПредставлений.Добавить(ЭлементСписка);
	
	Если ЭлементДанных.Свойство("Представление")
	   И ТипЗнч(ЭлементДанных.Представление) = Тип("Структура") Тогда
		
		ЗаполнитьЗначенияСвойств(ЭлементСписка, ЭлементДанных.Представление);
		Возврат;
	КонецЕсли;
	
	Если ЭлементДанных.Свойство("Представление")
	   И ТипЗнч(ЭлементДанных.Представление) <> Тип("Строка") Тогда
	
		ЭлементСписка.Значение = ЭлементДанных.Представление;
		
	ИначеЕсли ЭлементДанных.Свойство("Объект")
	        И ТипЗнч(ЭлементДанных.Объект) <> Тип("ОписаниеОповещения") Тогда
		
		ЭлементСписка.Значение = ЭлементДанных.Объект;
	КонецЕсли;
	
	Если ЭлементДанных.Свойство("Представление") Тогда
		ЭлементСписка.Представление = ЭлементДанных.Представление;
	КонецЕсли;
	
КонецПроцедуры

// Для процедур ПроверитьПодписьПослеСозданияМенеджераКриптографии,
// ПолучитьДанныеИзОписанияДанныхПродолжение.
//
Функция ВключениеСертификатовВПодписьСтрокой(ВключениеСертификатовВПодпись)
	
	Если ТипЗнч(ВключениеСертификатовВПодпись) <> Тип("РежимВключенияСертификатовКриптографии") Тогда
		Возврат ВключениеСертификатовВПодпись;
	КонецЕсли;
	
	Если ВключениеСертификатовВПодпись = РежимВключенияСертификатовКриптографии.НеВключать Тогда
		Возврат "НеВключать";
	ИначеЕсли ВключениеСертификатовВПодпись = РежимВключенияСертификатовКриптографии.ВключатьСертификатСубъекта Тогда
		Возврат "ВключатьСертификатСубъекта";
	Иначе
		Возврат "ВключатьПолнуюЦепочку";
	КонецЕсли;
	
КонецФункции

// Для процедур СохранитьСертификатПродолжение, СохранитьЗапросНаСертификатПослеУстановкиРасширения.

// Продолжение процедуры ПроверитьПодпись.
Процедура ПроверитьПодписьВМоделиСервиса(Контекст)
	
	Если Не ЭлектроннаяПодписьКлиент.ПроверятьЭлектронныеПодписиНаСервере() Тогда
		Контекст.Вставить("ПроверитьСертификатНаКлиенте");
		ПроверитьПодписьНаКлиентеВМоделиСервиса(Контекст);
		Возврат;
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ПроверитьПодпись.
Процедура ПроверитьПодписьНаКлиентеВМоделиСервиса(Контекст)
	
	Подпись = Контекст.Подпись;
	
	Если ТипЗнч(Подпись) = Тип("Строка") И ЭтоАдресВременногоХранилища(Подпись) Тогда
		Подпись = ПолучитьИзВременногоХранилища(Подпись);
	КонецЕсли;
	
	Контекст.Вставить("ДанныеПодписи", Подпись);
	Контекст.Вставить("МенеджерКриптографии", "СервисКриптографии");
	
	МодульСервисКриптографииКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииКлиент");
	МодульСервисКриптографииКлиент.ПроверитьПодпись(Новый ОписаниеОповещения(
		"ПроверитьПодписьНаКлиентеПослеПроверкиПодписиВМоделиСервиса", ЭтотОбъект, Контекст,
		"ПроверитьПодписьНаКлиентеПослеОшибкиПроверкиПодписи", ЭтотОбъект),
		Контекст.ДанныеПодписи,
		Контекст.ИсходныеДанные);
		
КонецПроцедуры

// Продолжение процедуры ПроверитьПодпись.
Асинх Процедура ПроверитьПодписьНаКлиентеПослеПроверкиПодписиВМоделиСервиса(Результат, Контекст) Экспорт
	
	Если Не Результат.Выполнено Тогда
		Если ТипЗнч(Контекст.РезультатПроверки) = Тип("Структура") Тогда
			Контекст.РезультатПроверки.ТребуетсяПроверка = Истина;
		КонецЕсли;
		ПроверитьПодписьНаКлиентеПослеОшибкиПроверкиПодписи(Результат.ИнформацияОбОшибке, Ложь, Контекст);
		Возврат;
	КонецЕсли;
	
	Если Не Результат.ПодписьДействительна Тогда
		ПроверитьПодписьНаКлиентеПослеОшибкиПроверкиПодписи(
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ТекстОшибкиСервисаПодписьНедействительна(),
				Ложь, Контекст);
		Возврат;
	КонецЕсли;
	
	ПроверитьПодписьНаКлиентеПослеПроверкиПодписи(Неопределено, Контекст);
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
Процедура ВыполнитьНаСторонеВМоделиСервиса(Результат, Контекст)
	
	Контекст.Вставить("СертификатКриптографии", Результат);
	
	Если Контекст.Операция = "Подписание" Тогда
		
		Если ЭлектроннаяПодписьКлиент.ОбщиеНастройки().ДоступнаУсовершенствованнаяПодпись И ЗначениеЗаполнено(Контекст.ОписаниеДанных.ТипПодписи) Тогда
			Если Контекст.ОписаниеДанных.ТипПодписи <> ПредопределенноеЗначение("Перечисление.ТипыПодписиКриптографии.БазоваяCAdESBES")
				И Контекст.ОписаниеДанных.ТипПодписи <> ПредопределенноеЗначение("Перечисление.ТипыПодписиКриптографии.ОбычнаяCMS") Тогда
				Ошибка = Новый Структура("ОписаниеОшибки", СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru='Недоступно подписание типом подписи %1 с помощью встроенного криптопровайдера.'"), Контекст.ОписаниеДанных.ТипПодписи));
				ВыполнитьНаСторонеПослеЦикла(Ошибка, Контекст);
				Возврат;
			КонецЕсли;
		КонецЕсли;

		СертификатПодписи = Новый Структура("Отпечаток",
			Base64Значение(Контекст.ОписаниеДанных.ВыбранныйСертификат.Отпечаток));
		МодульХранилищеСертификатовКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ХранилищеСертификатовКлиент");
		МодульХранилищеСертификатовКлиент.НайтиСертификат(Новый ОписаниеОповещения(
				"ВыполнитьНаСторонеПослеВыгрузкиСертификатаВМоделиСервиса", ЭтотОбъект, Контекст), СертификатПодписи);
		
	ИначеЕсли Контекст.Операция = "Шифрование" Тогда
		СвойстваСертификатов = Контекст.ОписаниеДанных.СертификатыШифрования;
		Если ТипЗнч(СвойстваСертификатов) = Тип("Строка") Тогда
			СвойстваСертификатов = ПолучитьИзВременногоХранилища(СвойстваСертификатов);
		КонецЕсли;
		Контекст.Вставить("Индекс", -1);
		Контекст.Вставить("СвойстваСертификатов", СвойстваСертификатов);
		Контекст.Вставить("СертификатыШифрования", Новый Массив);
		ВыполнитьНаСторонеПодготовкаСертификатовВМоделиСервисаЦиклНачало(Контекст);
		Возврат;
	Иначе
		ВыполнитьНаСторонеЦиклЗапуск(Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
Процедура ВыполнитьНаСторонеПодготовкаСертификатовВМоделиСервисаЦиклНачало(Контекст)
	
	Если Контекст.СвойстваСертификатов.Количество() <= Контекст.Индекс + 1 Тогда
		ВыполнитьНаСторонеЦиклЗапуск(Контекст);
		Возврат;
	КонецЕсли;
	Контекст.Индекс = Контекст.Индекс + 1;
	
	ВыполнитьНаСторонеПодготовкаСертификатовПослеИнициализацииСертификатаВМоделиСервиса(
		Контекст.СвойстваСертификатов[Контекст.Индекс].Сертификат, Контекст);
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
Процедура ВыполнитьНаСторонеПодготовкаСертификатовПослеИнициализацииСертификатаВМоделиСервиса(СертификатКриптографии, Контекст)
	
	Контекст.СертификатыШифрования.Добавить(СертификатКриптографии);
	
	ВыполнитьНаСторонеПодготовкаСертификатовВМоделиСервисаЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ВыполнитьНаСтороне.
// 
// Параметры:
//   РезультатПоиска - Структура:
//   * ОписаниеОшибки - ИнформацияОбОшибке
//   Контекст - Структура
//
Асинх Процедура ВыполнитьНаСторонеПослеВыгрузкиСертификатаВМоделиСервиса(РезультатПоиска, Контекст) Экспорт
	
	Если Не РезультатПоиска.Выполнено Тогда
		Ошибка = Новый Структура("ОписаниеОшибки", СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось найти сертификат в сервисе по причине:
			           |%1'"), РезультатПоиска.ОписаниеОшибки.Описание));
		ВыполнитьНаСторонеПослеЦикла(Ошибка, Контекст);
		Возврат;
	КонецЕсли;
	Если Не ЗначениеЗаполнено(РезультатПоиска.Сертификат) Тогда
		Ошибка = Новый Структура("ОписаниеОшибки",
			НСтр("ru = 'Сертификат отсутствует в сервисе (возможно удален).'"));
		ВыполнитьНаСторонеПослеЦикла(Ошибка, Контекст);
		Возврат;
	КонецЕсли;
	
	Контекст.Вставить("СвойстваСертификата", Ждать СвойстваСертификата(
		РезультатПоиска.Сертификат));
	Контекст.СвойстваСертификата.Вставить("ДвоичныеДанные", РезультатПоиска.Сертификат.Сертификат);
	
	ВыполнитьНаСторонеЦиклЗапуск(Контекст);
	
КонецПроцедуры

Функция ИспользоватьЭлектроннуюПодписьВМоделиСервиса() Экспорт
	
	Если ОбщегоНазначенияКлиент.ПодсистемаСуществует("ТехнологияСервиса.ЭлектроннаяПодписьВМоделиСервиса") Тогда
		МодульЭлектроннаяПодписьВМоделиСервисаКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьВМоделиСервисаКлиент");
		Возврат МодульЭлектроннаяПодписьВМоделиСервисаКлиент.ИспользованиеВозможно();
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

Функция ИспользованиеИнтерактивногоРежимаКриптографииИспользовать()
	
	Возврат Вычислить("ИспользованиеИнтерактивногоРежимаКриптографии.Использовать");
	
КонецФункции

Функция НачалоОписанияТекстаОшибки(ИмяМетода)
	
	Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Метод %1 не выполнен по причине:'"), ИмяМетода); 
	
КонецФункции

#Область ДобавлениеСертификата

// Продолжение процедуры ЭлектроннаяПодписьКлиент.ДобавитьСертификат.
Процедура ДобавитьСертификатПослеСозданияМенеджераКриптографии(Результат, Контекст) Экспорт
	
	Если ТипЗнч(Результат) <> Тип("МенеджерКриптографии")
		И Результат.Общая Тогда
		
		Результат.ЗаголовокОшибки = Контекст.ЗаголовокОшибкиПрограммы;
		Контекст.Вставить("ОшибкаНаКлиенте", Результат);
		ВыполнитьОбработкуОповещения(Контекст.ОбработчикЗавершения, Неопределено);
		СообщитьОбОшибкеДобавленияСертификата(Контекст);
		
		Возврат;
		
	КонецЕсли;
	
	СертификатКриптографии = Новый СертификатКриптографии;
	СертификатКриптографии.НачатьИнициализацию(Новый ОписаниеОповещения(
		"ДобавитьСертификатПослеИнициализацииСертификата", ЭтотОбъект, Контекст),
		Контекст.ДанныеСертификата);
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.ДобавитьСертификат.
Асинх Процедура ДобавитьСертификатПослеИнициализацииСертификата(СертификатКриптографии, Контекст) Экспорт
	
	Контекст.Вставить("СертификатКриптографии", СертификатКриптографии);
	
	Контекст.Вставить("ОшибкаНаКлиенте", 
		ЭлектроннаяПодписьСлужебныйКлиентСервер.НовоеОписаниеОшибок());
	
	Если Не Контекст.Свойство("АлгоритмПодписи") Тогда
		Контекст.Вставить("АлгоритмПодписи", "");
	КонецЕсли;
	
	Контекст.Вставить("ЭтоПолноправныйПользователь", ПользователиКлиент.ЭтоПолноправныйПользователь());
	
	ОписанияПрограмм = ЭлектроннаяПодписьКлиент.ОбщиеНастройки().ОписанияПрограмм;
	
	ПрограммаПоСертификатуРезультат = Ждать ПрограммаПоСертификату(СертификатКриптографии, Истина, Неопределено, Истина);
	Если ЗначениеЗаполнено(ПрограммаПоСертификатуРезультат.Программа) Тогда
		ОписанияПрограмм = ЭлектроннаяПодписьСлужебныйКлиентСервер.МенеджерКриптографииОписанияПрограмм(
			ПрограммаПоСертификатуРезультат.Программа, Контекст.ОшибкаНаКлиенте.Ошибки, ОписанияПрограмм);
	Иначе
		СвойстваОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.НовыеСвойстваОшибки();
		СвойстваОшибки.Описание = ПрограммаПоСертификатуРезультат.Ошибка;
		Контекст.ОшибкаНаКлиенте.Ошибки.Добавить(СвойстваОшибки);
	КонецЕсли;
		
	Контекст.Вставить("ОписанияПрограмм", ОписанияПрограмм);
	Контекст.Вставить("ОписаниеПрограммы", Неопределено);
	Контекст.Вставить("Индекс", -1);
	
	ДобавитьСертификатЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.ДобавитьСертификат.
// 
// Параметры:
//  Контекст - Структура:
//   * ОшибкаНаКлиенте - Структура:
//      ** Ошибки - Массив - ИнформацияОбОшибке
//   * ОписаниеПрограмм - см. ЭлектроннаяПодписьСлужебныйПовтИсп.ОписаниеПрограммы
//
Процедура ДобавитьСертификатЦиклНачало(Контекст)
	
	Если Контекст.ОписанияПрограмм.Количество() <= Контекст.Индекс + 1 Тогда
		
		ВыполнитьОбработкуОповещения(Контекст.ОбработчикЗавершения, Неопределено);
		СообщитьОбОшибкеДобавленияСертификата(Контекст);
		
		Возврат;
		
	КонецЕсли;
	
	Контекст.Индекс = Контекст.Индекс + 1;
	ОписаниеПрограммы = Контекст.ОписанияПрограмм[Контекст.Индекс]; // см. ЭлектроннаяПодписьСлужебныйПовтИсп.ОписаниеПрограммы
	Контекст.ОписаниеПрограммы = ОписаниеПрограммы;
	
	ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
	ПараметрыСоздания.ПоказатьОшибку = Неопределено;
	 
	ПараметрыСоздания.Программа = ОписаниеПрограммы;
	ПараметрыСоздания.ИнтерактивныйРежим = Контекст.ДополнительныеПараметры.ВводитьПарольВПрограммеЭлектроннойПодписи;
	ПараметрыСоздания.АлгоритмПодписи = Контекст.АлгоритмПодписи;
	
	СоздатьМенеджерКриптографии(
		Новый ОписаниеОповещения("ДобавитьСертификатЦиклПослеСозданияМенеджераКриптографии",ЭтотОбъект, Контекст),
		"", ПараметрыСоздания);
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.ДобавитьСертификат.
// 
// Параметры:
//   Контекст - Структура:
//     * ОшибкаНаКлиенте - Структура:
//         ** Ошибки - Массив
//
Процедура ДобавитьСертификатЦиклПослеСозданияМенеджераКриптографии(Результат, Контекст) Экспорт
	
	Если ТипЗнч(Результат) <> Тип("МенеджерКриптографии") Тогда
		
		Если Результат.Ошибки.Количество() > 0
		   И Не (ЗначениеЗаполнено(Контекст.АлгоритмПодписи)
		         И Результат.Ошибки[0].НетАлгоритма) Тогда
			
			Результат.Ошибки[0].ЗаголовокОшибки = Контекст.ЗаголовокОшибкиПрограммы;
			Контекст.ОшибкаНаКлиенте.Ошибки.Добавить(Результат.Ошибки[0]);
		КонецЕсли;
		
		ДобавитьСертификатЦиклНачало(Контекст);
		Возврат;
		
	КонецЕсли;
	
	Контекст.Вставить("МенеджерКриптографии", Результат);
	Если Не ИспользуетсяИнтерактивныйРежимКриптографии(Контекст.МенеджерКриптографии) Тогда
		Контекст.МенеджерКриптографии.ПарольДоступаКЗакрытомуКлючу = Контекст.ПарольСертификата;
	КонецЕсли;
	
	Если Контекст.ДляШифрования = Истина Тогда
		Контекст.МенеджерКриптографии.НачатьШифрование(Новый ОписаниеОповещения(
			"ДобавитьСертификатЦиклПослеШифрования", ЭтотОбъект, Контекст,
			"ДобавитьСертификатЦиклПослеОшибкиШифрования", ЭтотОбъект),
			Контекст.ДанныеСертификата, Контекст.СертификатКриптографии);
	Иначе
		Контекст.МенеджерКриптографии.НачатьПодписывание(Новый ОписаниеОповещения(
			"ДобавитьСертификатЦиклПослеПодписания", ЭтотОбъект, Контекст,
			"ДобавитьСертификатЦиклПослеОшибкиПодписания", ЭтотОбъект),
			Контекст.ДанныеСертификата, Контекст.СертификатКриптографии);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.ДобавитьСертификат.
Процедура ДобавитьСертификатЦиклПослеШифрования(ЗашифрованныеДанные, Контекст) Экспорт
	
	Контекст.МенеджерКриптографии.НачатьРасшифровку(Новый ОписаниеОповещения(
		"ДобавитьСертификатЦиклПослеРасшифровки", ЭтотОбъект, Контекст,
		"ДобавитьСертификатЦиклПослеОшибкиРасшифровки", ЭтотОбъект),
		ЗашифрованныеДанные);
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.ДобавитьСертификат.
// 
// Параметры:
//   Контекст - Структура:
//     * ОшибкаНаКлиенте - Структура:
//         ** Ошибки - Массив
//     * ОписаниеПрограмм - см. ЭлектроннаяПодписьСлужебныйПовтИсп.ОписаниеПрограммы
//
Процедура ДобавитьСертификатЦиклПослеОшибкиШифрования(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
	
	СтандартнаяОбработка = Ложь;
	
	ЭлектроннаяПодписьСлужебныйКлиентСервер.ЗаполнитьОшибкуДобавленияСертификата(
		Контекст.ОшибкаНаКлиенте,
		Контекст.ОписаниеПрограммы,
		"Шифрование",
		ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке),
		Контекст.ЭтоПолноправныйПользователь);
		
	ДобавитьСертификатЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.ДобавитьСертификат.
// 
// Параметры:
//   Контекст - Структура:
//    * ОписаниеОшибки - см. ЭлектроннаяПодписьСлужебныйПовтИсп.ОписаниеПрограммы
//
Процедура ДобавитьСертификатЦиклПослеПодписания(ДанныеПодписи, Контекст) Экспорт
	
	ИнформацияОбОшибке = Неопределено;
	ПредставлениеОшибки = "";
	Попытка
		ЭлектроннаяПодписьСлужебныйКлиентСервер.ПустыеДанныеПодписи(ДанныеПодписи, ПредставлениеОшибки);
	Исключение
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		ПредставлениеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
	КонецПопытки;
	
	Если ЗначениеЗаполнено(ПредставлениеОшибки) Тогда
		ЭлектроннаяПодписьСлужебныйКлиентСервер.ЗаполнитьОшибкуДобавленияСертификата(
			Контекст.ОшибкаНаКлиенте,
			Контекст.ОписаниеПрограммы,
			"Подписание",
			ПредставлениеОшибки,
			Контекст.ЭтоПолноправныйПользователь,
			ИнформацияОбОшибке = Неопределено);
		
		ДобавитьСертификатЦиклНачало(Контекст);
		Возврат;
	КонецЕсли;
	
	Сертификат = ЭлектроннаяПодписьСлужебныйКлиентСервер.ЗаписатьСертификатВСправочник(Контекст,
		Контекст.ОшибкаНаКлиенте);
	
	Если Сертификат = Неопределено Тогда
		СообщитьОбОшибкеДобавленияСертификата(Контекст);
	Иначе
		ВыполнитьОбработкуОповещения(Контекст.ОбработчикЗавершения, Сертификат);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.ДобавитьСертификат.
Процедура ДобавитьСертификатЦиклПослеОшибкиПодписания(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
	
	СтандартнаяОбработка = Ложь;
	
	ЭлектроннаяПодписьСлужебныйКлиентСервер.ЗаполнитьОшибкуДобавленияСертификата(
		Контекст.ОшибкаНаКлиенте,
		Контекст.ОписаниеПрограммы,
		"Подписание",
		ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке),
		Контекст.ЭтоПолноправныйПользователь);
	
	ДобавитьСертификатЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.ДобавитьСертификат.
// 
// Параметры:
//   Контекст - Структура
//
Процедура ДобавитьСертификатЦиклПослеРасшифровки(РасшифрованныеДанные, Контекст) Экспорт
	
	ИнформацияОбОшибке = Неопределено;
	ПредставлениеОшибки = "";
	Попытка
		ЭлектроннаяПодписьСлужебныйКлиентСервер.ПустыеРасшифрованныеДанные(РасшифрованныеДанные, ПредставлениеОшибки);
	Исключение
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		ПредставлениеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
	КонецПопытки;
	
	Если ЗначениеЗаполнено(ПредставлениеОшибки) Тогда
		ЭлектроннаяПодписьСлужебныйКлиентСервер.ЗаполнитьОшибкуДобавленияСертификата(
			Контекст.ОшибкаНаКлиенте,
			Контекст.ОписаниеПрограммы,
			"Расшифровка",
			ПредставлениеОшибки,
			Контекст.ЭтоПолноправныйПользователь,
			ИнформацияОбОшибке = Неопределено);
	
		ДобавитьСертификатЦиклНачало(Контекст);
		Возврат;
	КонецЕсли;
	
	Сертификат = ЭлектроннаяПодписьСлужебныйКлиентСервер.ЗаписатьСертификатВСправочник(Контекст,
		Контекст.ОшибкаНаКлиенте);
	
	Если Сертификат = Неопределено Тогда
		СообщитьОбОшибкеДобавленияСертификата(Контекст);
	Иначе
		ВыполнитьОбработкуОповещения(Контекст.ОбработчикЗавершения, Сертификат);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ЭлектроннаяПодписьКлиент.ДобавитьСертификат.
Процедура ДобавитьСертификатЦиклПослеОшибкиРасшифровки(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
	
	СтандартнаяОбработка = Ложь;
	
	ЭлектроннаяПодписьСлужебныйКлиентСервер.ЗаполнитьОшибкуДобавленияСертификата(
		Контекст.ОшибкаНаКлиенте,
		Контекст.ОписаниеПрограммы,
		"Расшифровка",
		ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке),
		Контекст.ЭтоПолноправныйПользователь);
	
	ДобавитьСертификатЦиклНачало(Контекст);
	
КонецПроцедуры

Процедура СообщитьОбОшибкеДобавленияСертификата(КонтекстДобавления)
	
	ОшибкаНаКлиенте = ?(КонтекстДобавления.Свойство("ОшибкаНаКлиенте"),
		КонтекстДобавления.ОшибкаНаКлиенте, Новый Структура);
	ОшибкаНаСервере = ?(КонтекстДобавления.Свойство("ОшибкаНаСервере"),
		КонтекстДобавления.ОшибкаНаСервере, Новый Структура);
	
	ДополнительныеПараметры = Новый Структура("Сертификат",
		КонтекстДобавления.ДанныеСертификата);
		
	Если ЗначениеЗаполнено(ОшибкаНаКлиенте) И ОшибкаНаКлиенте.Ошибки.Количество() > 0
		И ОшибкаНаКлиенте.Ошибки[0].Описание = ТекстОшибкиНеУдалосьОпределитьПрограммуПоЗакрытомуКлючуСертификата() Тогда
		
		ПараметрыОшибки = Новый Структура;
		ПараметрыОшибки.Вставить("ЗаголовокПредупреждения", КонтекстДобавления.ЗаголовокФормы);
		ПараметрыОшибки.Вставить("ТекстОшибкиКлиент", ОшибкаНаКлиенте.Ошибки[0].Описание);
		
		Если ЗначениеЗаполнено(ОшибкаНаСервере) И ОшибкаНаСервере.Ошибки.Количество() > 0 Тогда
			ПараметрыОшибки.Вставить("ТекстОшибкиСервер", ОшибкаНаСервере.Ошибки[0].Описание);
		КонецЕсли;
		
		ПараметрыОшибки.Вставить("ДополнительныеДанные", ДополнительныеПараметры);
		
		ОткрытьФорму("ОбщаяФорма.РасширенноеПредставлениеОшибки", ПараметрыОшибки, ЭтотОбъект);
		
	Иначе
		ПоказатьОшибкуОбращенияКПрограмме(КонтекстДобавления.ЗаголовокФормы,
			"", ОшибкаНаКлиенте, ОшибкаНаСервере, ДополнительныеПараметры);
	КонецЕсли;
КонецПроцедуры

#КонецОбласти

#Область ОперацииСОблачнойПодписью

Процедура ВыполнитьНаСторонеОблачнойПодписи(Контекст)
	
	ОписаниеДанных = Контекст.ОписаниеДанных;
	
	Контекст.Вставить("СертификатКриптографии", Null);
	
	Если Контекст.Операция = "Подписание" Тогда
		
		МодульСервисКриптографииDSSКлиентСервер = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSКлиентСервер");
		ВыбранныйСертификат = ОписаниеДанных.ВыбранныйСертификат;
		
		Отпечаток = Новый Структура();
		Отпечаток.Вставить("Отпечаток", МодульСервисКриптографииDSSКлиентСервер.ТрансформироватьОтпечаток(ВыбранныйСертификат.Отпечаток));
		Отпечаток.Вставить("ДвоичныеДанные", ПолучитьИзВременногоХранилища(ВыбранныйСертификат.Данные));
		
		СвойстваОблачнойПодписи = ПолучитьСвойстваОблачнойПодписи(ОписаниеДанных);
		НашлиСертификат = МодульСервисКриптографииDSSКлиентСервер.НайтиСертификат(СвойстваОблачнойПодписи.УчетнаяЗапись, Отпечаток);
		
		Если НашлиСертификат.Идентификатор = -1 Тогда
			Ошибка = Новый Структура("ОписаниеОшибки", ТекстОшибкиОблачнаяПодпись("ПоискСертификата"));
			Контекст.Вставить("ОперацияНачалась", Ложь);
			ВыполнитьНаСторонеПослеЦикла(Ошибка, Контекст);
			Возврат;
		КонецЕсли;
		
		НашлиСертификат.Вставить("ДвоичныеДанные", Отпечаток.ДвоичныеДанные);
		
		Контекст.Вставить("СвойстваСертификата", НашлиСертификат);
		
	ИначеЕсли Контекст.Операция = "Шифрование" Тогда
		СвойстваСертификатов = ОписаниеДанных.СертификатыШифрования;
		Если ТипЗнч(СвойстваСертификатов) = Тип("Строка") Тогда
			СвойстваСертификатов = ПолучитьИзВременногоХранилища(СвойстваСертификатов);
		КонецЕсли;
		
		СертификатыШифрования = Новый Массив;
		
		Для каждого СтрокаМассива Из СвойстваСертификатов Цикл
			СертификатыШифрования.Добавить(СтрокаМассива);
		КонецЦикла;
		
		Контекст.Вставить("Индекс", СертификатыШифрования.Количество());
		Контекст.Вставить("СвойстваСертификатов", СвойстваСертификатов);
		Контекст.Вставить("СертификатыШифрования", СертификатыШифрования);
		
	КонецЕсли;
	
	ВыполнитьНаСторонеЦиклЗапуск(Контекст);
	
КонецПроцедуры

Процедура ВыполнитьОперациюОблачнойПодписи(Оповещение, Контекст, Данные, ПараметрыОперации)
	
	ОписаниеДанных = Контекст.ОписаниеДанных;
	ИндексДанных = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Контекст, "Индекс", 0);
	ВыполнитьСразу = Истина;
	ТипРезультата = Неопределено;
			
	ИдентификаторТранзакции = Неопределено;
	СвойстваОблачнойПодписи = ПолучитьСвойстваОблачнойПодписи(ОписаниеДанных);
	ДанныеПодтверждения = СвойстваОблачнойПодписи.ДанныеПодтверждения;
	Если ДанныеПодтверждения <> Неопределено Тогда
		ИдентификаторТранзакции = ?(ЗначениеЗаполнено(ДанныеПодтверждения.ИдентификаторТранзакции), ДанныеПодтверждения.ИдентификаторТранзакции, ДанныеПодтверждения.ИдентификаторОперации);
	КонецЕсли;
	
	Если Контекст.Операция = "Подписание" Тогда
		МодульСервисКриптографииDSSКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSКлиент");
		ЗначениеПинКода = ?(ЗначениеЗаполнено(Контекст.ЗначениеПароля), Контекст.ЗначениеПароля, Неопределено);
		ПинКод = МодульСервисКриптографииDSSКлиент.ПодготовитьОбъектПароля(ЗначениеПинКода);
		ПараметрыОперации.Вставить("ПинКод", ПинКод);
		
		Если ДанныеПодтверждения <> Неопределено Тогда
			ПакетнаяОперация = ДанныеПодтверждения.ПараметрыВариантаВстроенного.ПакетнаяОперация;
			ТипРезультата = ДанныеПодтверждения.ПараметрыВариантаВстроенного.ТипРезультата;
			Если ЗначениеЗаполнено(ИдентификаторТранзакции)
				И ИндексДанных > 0
				И НЕ ПакетнаяОперация Тогда
				ВыполнитьСразу = Ложь;
			КонецЕсли;
			ПараметрыОперации.Вставить("ИдентификаторТранзакции", ИдентификаторТранзакции);
			ПараметрыОперации.Вставить("ПакетнаяПодпись", ПакетнаяОперация);
		КонецЕсли;	
		
		Если ВыполнитьСразу Тогда
			Если ЗначениеЗаполнено(ИдентификаторТранзакции) Тогда
				ПодписатьОблачнаяПодпись(Оповещение, Контекст, Неопределено, ПараметрыОперации, ТипРезультата);
			ИначеЕсли СвойстваОблачнойПодписи.ДанныеПакета = Неопределено Тогда
				ПодписатьОблачнаяПодпись(Оповещение, Контекст, Данные, ПараметрыОперации, ТипРезультата);
			Иначе
				ПодписатьОблачнаяПодпись(Оповещение, Контекст, СвойстваОблачнойПодписи.ДанныеПакета, ПараметрыОперации, ТипРезультата);
			КонецЕсли;	
		КонецЕсли;
					
	ИначеЕсли Контекст.Операция = "Шифрование" Тогда
		ШифроватьОблачнаяПодпись(Оповещение, Контекст, Данные, ПараметрыОперации, ТипРезультата);
		
	ИначеЕсли Контекст.Операция = "Расшифровка" Тогда
		ТипРезультата = Неопределено;
		МодульСервисКриптографииDSSКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSКлиент");
		ЗначениеПинКода = ?(ЗначениеЗаполнено(Контекст.ЗначениеПароля), Контекст.ЗначениеПароля, Неопределено);
		ПинКод = МодульСервисКриптографииDSSКлиент.ПодготовитьОбъектПароля(Контекст.ЗначениеПароля);
		ПараметрыОперации.Вставить("ПинКод", ПинКод);
		
		Если ДанныеПодтверждения <> Неопределено Тогда
			ТипРезультата = ДанныеПодтверждения.ПараметрыВариантаВстроенного.ТипРезультата;
			Если ЗначениеЗаполнено(ИдентификаторТранзакции)
				И ИндексДанных > 0 Тогда
				ВыполнитьСразу = Ложь;
			КонецЕсли;
			ПараметрыОперации.Вставить("ИдентификаторТранзакции", ИдентификаторТранзакции);
		КонецЕсли;
		
		Если ВыполнитьСразу Тогда
			РасшифроватьОблачнаяПодпись(Оповещение, Контекст, Данные, ПараметрыОперации, ТипРезультата);
		КонецЕсли;	
		
	КонецЕсли;
	
	Если НЕ ВыполнитьСразу Тогда
		ПараметрыПодтверждения = Новый Структура();
		ПараметрыПодтверждения.Вставить("Оповещение", Оповещение);
		ПараметрыПодтверждения.Вставить("Контекст", Контекст);
		ПараметрыПодтверждения.Вставить("Данные", Данные);
		ПараметрыПодтверждения.Вставить("ПараметрыОперации", ПараметрыОперации);
		ПараметрыПодтверждения.Вставить("ТипРезультата", ТипРезультата);
		
		ОповещениеПриВыполнении = Новый ОписаниеОповещения("ВыполнитьОперациюОблачнойПодписиПослеПодтверждения", ЭтотОбъект, ПараметрыПодтверждения); 
		УстановитьСвойстваОблачнойПодписи(Контекст.ОписаниеДанных,
			Новый Структура("ОповещениеПриПодтверждении", ОповещениеПриВыполнении));
			
		МодульСервисКриптографииDSSПодтверждениеКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSПодтверждениеКлиент");
		МодульСервисКриптографииDSSПодтверждениеКлиент.ВыполнитьНачальнуюОперациюСервиса(
					Контекст.Форма, 
					Контекст.ОписаниеДанных, 
					Контекст.ЗначениеПароля, 
					ИндексДанных);
	КонецЕсли;	
				
КонецПроцедуры	

Процедура ВыполнитьОперациюОблачнойПодписиПослеПодтверждения(РезультатВыполнения, ВходящийКонтекст) Экспорт
	
	Контекст = ВходящийКонтекст.Контекст;
	
	Если Контекст.Операция = "Подписание" Тогда
		ПодписатьОблачнаяПодпись(ВходящийКонтекст.Оповещение, ВходящийКонтекст.Контекст, ВходящийКонтекст.Данные, ВходящийКонтекст.ПараметрыОперации, ВходящийКонтекст.ТипРезультата);
	ИначеЕсли Контекст.Операция = "Расшифровка" Тогда
		РасшифроватьОблачнаяПодпись(ВходящийКонтекст.Оповещение, ВходящийКонтекст.Контекст, ВходящийКонтекст.Данные, ВходящийКонтекст.ПараметрыОперации, ВходящийКонтекст.ТипРезультата);
	КонецЕсли;	
	
КонецПроцедуры

Процедура ПодписатьОблачнаяПодпись(Оповещение, Контекст, Данные, ПараметрыОперации, ТипРезультата = Неопределено)
	
	МодульСервисКриптографииDSSКлиентСервер = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSКлиентСервер");
	МодульСервисКриптографииDSSКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSКлиент");
	
	Если ЭлектроннаяПодписьКлиент.ОбщиеНастройки().ДоступнаУсовершенствованнаяПодпись И ЗначениеЗаполнено(Контекст.ОписаниеДанных.ТипПодписи) Тогда
		Если Контекст.ОписаниеДанных.ТипПодписи = ПредопределенноеЗначение("Перечисление.ТипыПодписиКриптографии.БазоваяCAdESBES") Тогда
			СвойствоПодписи = МодульСервисКриптографииDSSКлиентСервер.ПолучитьСвойствоПодписиCAdES("BES", Истина, Ложь, "Подпись");
		ИначеЕсли Контекст.ОписаниеДанных.ТипПодписи = ПредопределенноеЗначение("Перечисление.ТипыПодписиКриптографии.СМеткойДоверенногоВремениCAdEST") Тогда
			АдресаСерверовМетокВремени = СтрСоединить(ЭлектроннаяПодписьКлиент.ОбщиеНастройки().АдресаСерверовМетокВремени, ",");
			СвойствоПодписи = МодульСервисКриптографииDSSКлиентСервер.ПолучитьСвойствоПодписиCAdES("T", Истина, Ложь, "Подпись" ,АдресаСерверовМетокВремени);
		ИначеЕсли Контекст.ОписаниеДанных.ТипПодписи = ПредопределенноеЗначение("Перечисление.ТипыПодписиКриптографии.ОбычнаяCMS") Тогда
			СвойствоПодписи = МодульСервисКриптографииDSSКлиентСервер.ПолучитьСвойствоПодписиCMS(Истина, Ложь);
		Иначе
			Ошибка = Новый Структура("ОписаниеОшибки", СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru='Недоступно подписание типом подписи %1 с помощью учетной записи DSS.'"), Контекст.ОписаниеДанных.ТипПодписи));
			ВыполнитьНаСторонеПослеЦикла(Ошибка, Контекст);
			Возврат;
		КонецЕсли;
	Иначе
		СвойствоПодписи = МодульСервисКриптографииDSSКлиентСервер.ПолучитьСвойствоПодписиCMS(Истина, Ложь);
	КонецЕсли;
	
	Если ТипРезультата <> Неопределено Тогда
		ПараметрыОперации.Вставить("ТрансформироватьРезультат", Новый Структура("ТипРезультата", ТипРезультата));
	КонецЕсли;
	
	СвойстваОблачнойПодписи = ПолучитьСвойстваОблачнойПодписи(Контекст.ОписаниеДанных);
	
	МодульСервисКриптографииDSSКлиент.Подписать(
				Оповещение,
				СвойстваОблачнойПодписи.УчетнаяЗапись,
				Данные, 
				СвойствоПодписи, 
				Контекст.СвойстваСертификата, 
				ПараметрыОперации);
	
КонецПроцедуры

Процедура ШифроватьОблачнаяПодпись(Оповещение, Контекст, Данные, ПараметрыОперации, ТипРезультата = Неопределено)
	
	Если ТипРезультата <> Неопределено Тогда
		ПараметрыОперации.Вставить("ТрансформироватьРезультат", Новый Структура("ТипРезультата", ТипРезультата));
	КонецЕсли;
	
	СвойстваОблачнойПодписи = ПолучитьСвойстваОблачнойПодписи(Контекст.ОписаниеДанных);
	
	МодульСервисКриптографииDSSКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSКлиент");
	МодульСервисКриптографииDSSКлиент.Зашифровать(
				Оповещение,
				СвойстваОблачнойПодписи.УчетнаяЗапись,
				Данные,
				Контекст.СертификатыШифрования,
				"CMS", 
				ПараметрыОперации);
	
КонецПроцедуры

Процедура РасшифроватьОблачнаяПодпись(Оповещение, Контекст, Данные, ПараметрыОперации, ТипРезультата = Неопределено)
	
	МодульСервисКриптографииDSSКлиентСервер = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSКлиентСервер");
	МодульСервисКриптографииDSSКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSКлиент");
	
	Если ТипРезультата <> Неопределено Тогда
		ПараметрыОперации.Вставить("ТрансформироватьРезультат", Новый Структура("ТипРезультата", ТипРезультата));
	КонецЕсли;
	
	Сертификат = Новый Структура("Отпечаток", МодульСервисКриптографииDSSКлиентСервер.ТрансформироватьОтпечаток(Контекст.ОписаниеДанных.ВыбранныйСертификат.Отпечаток));
	СвойстваОблачнойПодписи = ПолучитьСвойстваОблачнойПодписи(Контекст.ОписаниеДанных);
	
	МодульСервисКриптографииDSSКлиент.Расшифровать(
				Оповещение,
				СвойстваОблачнойПодписи.УчетнаяЗапись,
				Данные,
				"CMS",
				Сертификат,
				ПараметрыОперации);
	
КонецПроцедуры

Асинх Процедура ВыполнитьНаСторонеЦиклПослеПодписанияПакета(МассивПодписей, Контекст)
	
	ОшибкаНаКлиенте = Неопределено;
	
	Для Счетчик = 0 По МассивПодписей.Количество() - 1 Цикл
		
		ДвоичныеДанные = МассивПодписей[Счетчик];
		
		СвойстваПодписи = Ждать СвойстваПодписиИзДвоичныхДанных(ДвоичныеДанные, Ложь);
		СвойстваПодписи = ПолучитьСвойстваПодписиПослеПодписания(ДвоичныеДанные, Контекст, СвойстваПодписи);

		ЭлементДанных = Контекст.ОписаниеДанных.НаборДанных[Счетчик];
		ЭлементДанных.Вставить("СвойстваПодписи", СвойстваПодписи);
		
		Если Не ЭлементДанных.Свойство("Объект") Тогда
			ЭлектроннаяПодписьСлужебныйВызовСервера.ЗарегистрироватьПодписаниеДанныхВЖурнале(
				СвойстваТекущегоЭлементаДанных(Контекст, СвойстваПодписи));
			Продолжить;
		КонецЕсли;
		
		Если ТипЗнч(ЭлементДанных.Объект) <> Тип("ОписаниеОповещения") Тогда
			ВерсияОбъекта = Неопределено;
			ЭлементДанных.Свойство("ВерсияОбъекта", ВерсияОбъекта);
			СвойстваПодписи.Вставить("ИдентификаторПодписи", Строка(Новый УникальныйИдентификатор));
			ПредставлениеОшибки = ЭлектроннаяПодписьСлужебныйВызовСервера.ДобавитьПодпись(
				ЭлементДанных.Объект, СвойстваПодписи, Контекст.ИдентификаторФормы, ВерсияОбъекта);
			Если ЗначениеЗаполнено(ПредставлениеОшибки) Тогда
				ОшибкаНаКлиенте = Новый Структура("ОписаниеОшибки", ПредставлениеОшибки);
				ЭлементДанных.Удалить("СвойстваПодписи");
				Продолжить;
			КонецЕсли;
			ОповеститьОбИзменении(ЭлементДанных.Объект);
			
		Иначе // сделать отдельную ветку для возврата в цикл по счетчику
			ЭлектроннаяПодписьСлужебныйВызовСервера.ЗарегистрироватьПодписаниеДанныхВЖурнале(
				СвойстваТекущегоЭлементаДанных(Контекст, СвойстваПодписи));
				
			ПараметрыВыполнения = Новый Структура;
			ПараметрыВыполнения.Вставить("ОписаниеДанных", Контекст.ОписаниеДанных);
			ПараметрыВыполнения.Вставить("Оповещение", Новый ОписаниеОповещения(
				"ВыполнитьНаСторонеЦиклПослеЗаписиПодписи", ЭтотОбъект, Контекст));
			
			Попытка
				ВыполнитьОбработкуОповещения(ЭлементДанных.Объект, ПараметрыВыполнения);
			Исключение
				ИнформацияОбОшибке = ИнформацияОбОшибке();
				ОшибкаНаКлиенте = Новый Структура("ОписаниеОшибки", ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
			КонецПопытки;
			
		КонецЕсли;
		
	КонецЦикла;
	
	Если ОшибкаНаКлиенте <> Неопределено Тогда
		ВыполнитьНаСторонеПослеЦикла(ОшибкаНаКлиенте, Контекст);
	Иначе
		Контекст.Индекс = 0;
		ВыполнитьНаСторонеПослеЦикла(Неопределено, Контекст);
	КонецЕсли;	

КонецПроцедуры

Функция ПроверятьСертификатыОблачнойПодписью()
	
	Результат = ИспользоватьСервисОблачнойПодписи()
				И ЭлектроннаяПодписьСлужебныйВызовСервера.НастроенСервисОблачнойПодписи();
	
	Возврат Результат;
	
КонецФункции

Функция ШифроватьДанныеОблачнойПодписью()
	
	Результат = ИспользоватьСервисОблачнойПодписи()
				И ЭлектроннаяПодписьСлужебныйВызовСервера.НастроенСервисОблачнойПодписи();
	Результат = Ложь;
	
	Возврат Результат;
	
КонецФункции

// Продолжение процедуры ПроверитьСертификат.
Процедура ПроверитьСертификатОблачнаяПодпись(Контекст, РегистрироватьОшибки = Истина)
	
	Контекст.Вставить("РегистрироватьОшибкиОблачногоСервиса", РегистрироватьОшибки);
	
	Если ТипЗнч(Контекст.Сертификат) = Тип("СертификатКриптографии") Тогда
		Контекст.Сертификат.НачатьВыгрузку(Новый ОписаниеОповещения(
			"ПроверитьСертификатОблачнаяПодписьПослеВыгрузкиСертификата", ЭтотОбъект, Контекст));
	ИначеЕсли ТипЗнч(Контекст.Сертификат) = Тип("Структура") Тогда
		ПроверитьСертификатОблачнаяПодписьПослеВыгрузкиСертификата(Контекст.Сертификат.Сертификат, Контекст);
	Иначе
		ПроверитьСертификатОблачнаяПодписьПослеВыгрузкиСертификата(Контекст.Сертификат, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ПроверитьСертификат.
Процедура ПроверитьСертификатОблачнаяПодписьПослеВыгрузкиСертификата(Сертификат, Контекст) Экспорт
	
	Если ТипЗнч(Сертификат) = Тип("ДвоичныеДанные") Тогда
		ДанныеСертификата = Сертификат;
	Иначе
		ДанныеСертификата = ПолучитьИзВременногоХранилища(Сертификат);
	КонецЕсли;
	
	Если Не Контекст.РегистрироватьОшибкиОблачногоСервиса Тогда
		ПараметрыОперации = Новый Структура("РегистрироватьОшибку", Ложь);
	Иначе
		ПараметрыОперации = Неопределено;
	КонецЕсли;
	
	МодульСервисКриптографииDSSКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSКлиент");
	МодульСервисКриптографииDSSКлиент.ПроверитьСертификат(
		Новый ОписаниеОповещения("ПроверитьСертификатПослеПроверкиОблачнаяПодпись", ЭтотОбъект, Контекст),
		Неопределено,
		ДанныеСертификата,
		ПараметрыОперации);
	
КонецПроцедуры

// Продолжение процедуры ПроверитьСертификат.
Процедура ПроверитьСертификатПослеПроверкиОблачнаяПодпись(РезультатВызова, Контекст) Экспорт
	
	Если Не РезультатВызова.Выполнено Тогда
		Контекст.ОписаниеОшибкиНаСервере = 
			ТекстОшибкиОблачнаяПодпись("ПроверкаСертификата", РезультатВызова, Истина);
		ПроверитьСертификатПослеНеуспешнойПроверки(Контекст);
		Возврат;
	КонецЕсли;
	
	Если Не РезультатВызова.Результат Тогда
		Контекст.ОписаниеОшибкиНаСервере = ТекстОшибкиОблачнаяПодпись("ПроверкаСертификата", РезультатВызова, Ложь);
		ОбработатьОшибкуПоКлассификатору(Контекст.ОписаниеОшибкиНаСервере, Контекст.ТребуетПроверкиНаСервере, Контекст);
		ПроверитьСертификатПослеНеуспешнойПроверки(Контекст);
		Возврат;
	КонецЕсли;
	
	ДополнительнаяПроверкаСертификата(Контекст.СертификатКриптографии, Истина, Контекст);
	
КонецПроцедуры

Процедура ОбработатьОшибкуПоКлассификатору(ТекстОшибки, ТребуетПроверки, Контекст, ОшибкаПоКлассификатору = Неопределено)
	
	Если ОшибкаПоКлассификатору = Неопределено Тогда
		ОшибкаПоКлассификатору = ЭлектроннаяПодписьСлужебныйКлиентПовтИсп.ОшибкаПоКлассификатору(ТекстОшибки);
	КонецЕсли;
	
	Если ОшибкаПоКлассификатору = Неопределено Тогда
		Возврат;
	КонецЕсли;

	Если ОшибкаПоКлассификатору.СертификатОтозван Тогда
		Контекст.СертификатОтозван = Истина;
		Попытка
			СсылкаНаСертификат = ЭлектроннаяПодписьСлужебныйВызовСервера.ЗаписатьОтметкуОбОтзывеСертификата(
				Base64Строка(Контекст.СертификатКриптографии.Отпечаток));
			Если ЗначениеЗаполнено(СсылкаНаСертификат) Тогда
				ДополнительныеПараметры = ПараметрыОповещенияПриЗаписиСертификата();
				ДополнительныеПараметры.Отозван = Истина;
				Оповестить("Запись_СертификатыКлючейЭлектроннойПодписиИШифрования", ДополнительныеПараметры,
					СсылкаНаСертификат);
			КонецЕсли;
		Исключение
			Ошибка = Ошибка + Символы.ПС
				+ ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
		КонецПопытки;
	Иначе
		ТребуетПроверки = ОшибкаПоКлассификатору.ТребуетПроверки;
	КонецЕсли;
		
КонецПроцедуры

// Продолжение процедуры ПроверитьПодпись.
Процедура ПроверитьПодписьОблачнаяПодпись(Контекст)
	
	Если ТипЗнч(Контекст.ИсходныеДанные) = Тип("Строка")
		И ЭтоАдресВременногоХранилища(Контекст.ИсходныеДанные) Тогда
		Контекст.ИсходныеДанные = ПолучитьИзВременногоХранилища(Контекст.ИсходныеДанные);
	КонецЕсли;
	
	Контекст.Вставить("МенеджерКриптографии", "ОблачнаяПодпись");
	Контекст.Вставить("ПроверитьСертификатНаКлиенте");
	
	ПроверитьПодписьНаКлиентеОблачнаяПодпись(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ПроверитьПодпись.
Процедура ПроверитьПодписьНаКлиентеОблачнаяПодпись(Контекст)
	
	Подпись = Контекст.Подпись;
	ИсходныеДанные = Контекст.ИсходныеДанные;
	
	Если ТипЗнч(Подпись) = Тип("Строка") И ЭтоАдресВременногоХранилища(Подпись) Тогда
		Подпись = ПолучитьИзВременногоХранилища(Подпись);
	КонецЕсли;
	
	Если ТипЗнч(ИсходныеДанные) = Тип("Строка") И ЭтоАдресВременногоХранилища(ИсходныеДанные) Тогда
		ИсходныеДанные = ПолучитьИзВременногоХранилища(ИсходныеДанные);
	КонецЕсли;
	
	Контекст.Вставить("ДанныеПодписи", Подпись);
	Контекст.Вставить("МенеджерКриптографии", "ОблачнаяПодпись");
	
	ОбработчикСледующий = Новый ОписаниеОповещения(
		"ПроверитьПодписьНаКлиентеПослеПроверкиПодписиОблачнаяПодпись", ЭтотОбъект, Контекст,
		"ПроверитьПодписьНаКлиентеПослеОшибкиПроверкиПодписи", ЭтотОбъект);
	
	МодульСервисКриптографииDSSКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSКлиент");
	МодульСервисКриптографииDSSКлиент.ПроверитьПодпись(
		ОбработчикСледующий,
		Неопределено,
		Контекст.ДанныеПодписи,
		ИсходныеДанные,
		"CMS");
		
КонецПроцедуры

// Продолжение процедуры ПроверитьПодпись.
Процедура ПроверитьПодписьНаКлиентеПослеПроверкиПодписиОблачнаяПодпись(РезультатВызова, Контекст) Экспорт
	
	Если Не РезультатВызова.Выполнено Тогда
		ТекстОшибки = ТекстОшибкиОблачнаяПодпись("ПроверкаПодписи", РезультатВызова, Истина);
		ПроверитьПодписьНаКлиентеПослеОшибкиПроверкиПодписи(ТекстОшибки, Ложь, Контекст);
		Возврат;
	КонецЕсли;
	
	Если Не РезультатВызова.Результат Тогда
		ТекстОшибки = ТекстОшибкиОблачнаяПодпись("ПроверкаПодписи", РезультатВызова, Ложь);
		ПроверитьПодписьНаКлиентеПослеОшибкиПроверкиПодписи(ТекстОшибки, Ложь, Контекст);
		Возврат;
	КонецЕсли;
	
	ПроверитьПодписьНаКлиентеПослеПроверкиПодписи(Неопределено, Контекст);
	
КонецПроцедуры

Функция ИспользоватьСервисОблачнойПодписи() Экспорт
	
	Если ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодписьСервисаDSS") Тогда
		МодульСервисКриптографииDSSКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSКлиент");
		Возврат МодульСервисКриптографииDSSКлиент.ИспользоватьСервисОблачнойПодписи();
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

Функция ТипПрограммыСервисаПодписи() Экспорт
	
	Результат = Неопределено;
	
	Если ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодписьСервисаDSS") Тогда
		МодульСервисКриптографииDSSКлиентСервер = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSКлиентСервер");
		Результат = МодульСервисКриптографииDSSКлиентСервер.ПолучитьТипОблачнойПодписи();
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция ЭтоОперацияОблачнойПодписи(КонтекстФормы) Экспорт
	
	Результат = Ложь;
	
	Если ИспользоватьСервисОблачнойПодписи() Тогда
		ТекущиеДанные = ПолучитьДанныеОблачнойПодписи(КонтекстФормы, "ДанныеСертификата");
		Если ТипЗнч(ТекущиеДанные) = Тип("Структура") Тогда
			Результат = ТекущиеДанные.Облачный;
		КонецЕсли;		
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Процедура СброситьПарольВПамяти(СертификатСсылка) Экспорт
	
	ФормаПередачаПараметров().СброситьПарольСертификата(СертификатСсылка);

КонецПроцедуры

Функция УстановитьСвойстваОблачнойПодписи(ОписаниеДанных, НовыеЗначения) Экспорт
	
	ДанныеОблачнойПодписи = ПолучитьСвойстваОблачнойПодписи(ОписаниеДанных);
	
	ЗаполнитьЗначенияСвойств(ДанныеОблачнойПодписи, НовыеЗначения);
	
	Возврат ДанныеОблачнойПодписи;
	
КонецФункции

Функция ПолучитьСвойстваОблачнойПодписи(ОписаниеДанных) Экспорт
	
	ИмяКлюча = "СвойстваОблачнойПодписи";
	ДанныеОблачнойПодписи = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ОписаниеДанных, ИмяКлюча);
	
	Если ДанныеОблачнойПодписи = Неопределено Тогда
		Результат = Новый Структура();
		Результат.Вставить("УчетнаяЗапись", Неопределено);
		Результат.Вставить("ОповещениеПриПодтверждении", Неопределено);
		Результат.Вставить("ДанныеПакета", Неопределено);
		Результат.Вставить("ДанныеПодтверждения", Неопределено);
		ОписаниеДанных.Вставить(ИмяКлюча, Результат);
	Иначе
		Результат = ДанныеОблачнойПодписи;
	КонецЕсли;	
	
	Возврат Результат;
	
КонецФункции

Процедура ПолучитьДанныеДляОблачнойПодписи(Оповещение, Форма, ОписаниеДанных, ИсточникДанных, ДляСтороныКлиента) Экспорт
	
	ПолучитьДанныеИзОписанияДанных(Оповещение, Форма, ОписаниеДанных, ИсточникДанных, ДляСтороныКлиента);
	
КонецПроцедуры

Функция ПолучитьДанныеОблачнойПодписи(КонтекстФормы, ИмяРеквизита) Экспорт
	
	Результат = Неопределено;
	
	Если ИспользоватьСервисОблачнойПодписи() Тогда
		МодульСервисКриптографииDSSПодтверждениеКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSПодтверждениеКлиент");
		РеестрИмен = МодульСервисКриптографииDSSПодтверждениеКлиент.БазовыйРеестрРеквизитов(КонтекстФормы, Истина);
		Если РеестрИмен <> Неопределено Тогда
			РеквизитыФормы = Новый Структура(РеестрИмен[ИмяРеквизита], Неопределено);
			ЗаполнитьЗначенияСвойств(РеквизитыФормы, КонтекстФормы);
			Результат = РеквизитыФормы[РеестрИмен[ИмяРеквизита]];
		КонецЕсли;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Возвращает адаптированный текст ошибки при операции в сервисе DSS.
// 
// Параметры:
//  Операция - Строка - "ПроверкаПодписи", "ПроверкаСертификата", "ПоискСертификата",
//                      "Подписание", "Шифрование","Расшифровка"
//  РезультатВызова - Неопределено, Структура
//  ЭтоОшибкаВыполнения - Булево - это ошибка выполнения
// 
// Возвращаемое значение:
//  Строка - текст ошибки облачной подписи
//
Функция ТекстОшибкиОблачнаяПодпись(Операция, РезультатВызова = Неопределено, ЭтоОшибкаВыполнения = Ложь) Экспорт
	
	АдресСервера = "";
	ИсходныйТекст = "";
	
	Если ТипЗнч(РезультатВызова) = Тип("Структура") Тогда
		Если РезультатВызова.Свойство("НастройкиПользователя") Тогда
			АдресСервера = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(РезультатВызова.НастройкиПользователя, "Сервер", "");
		КонецЕсли;
		Если РезультатВызова.Свойство("СтатусОшибки") Тогда
			ИсходныйТекст = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(РезультатВызова.СтатусОшибки, "ИсходныйТекст", "");
		КонецЕсли;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ИсходныйТекст) Тогда
		ТекстОшибки = ИсходныйТекст;
		Если ЭтоОшибкаВыполнения И ЗначениеЗаполнено(АдресСервера) Тогда
			ТекстОшибки = ТекстОшибки + " " + НСтр("ru = 'на сервере'") + " " + СокрЛП(АдресСервера);
		КонецЕсли;
		
	ИначеЕсли Операция = "ПроверкаПодписи" Тогда
		Если ЭтоОшибкаВыполнения Тогда
			ТекстОшибки = НСтр("ru = 'Не удалось проверить подпись.'");
		Иначе
			ТекстОшибки = НСтр("ru = 'Подпись недействительна.'");
		КонецЕсли;
		
	ИначеЕсли Операция = "ПроверкаСертификата" Тогда
		Если ЭтоОшибкаВыполнения Тогда
			ТекстОшибки = НСтр("ru = 'Не удалось проверить сертификат.'");
		Иначе
			ТекстОшибки = НСтр("ru = 'Сертификат недействителен.'");
		КонецЕсли;
		
	ИначеЕсли Операция = "ПоискСертификата" Тогда
		ТекстОшибки = НСтр("ru = 'Не удалось найти сертификат (возможно удален).'");
		
	ИначеЕсли Операция = "Подписание" Тогда
		ТекстОшибки = НСтр("ru = 'Не удалось создать подпись.'");
		
	ИначеЕсли Операция = "Шифрование" Тогда
		ТекстОшибки = НСтр("ru = 'Не удалось зашифровать данные.'");
		
	ИначеЕсли Операция = "Расшифровка" Тогда
		ТекстОшибки = НСтр("ru = 'Не удалось расшифровать данные.'");
	Иначе
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Неизвестная операция ""%1"".'"), Операция);
	КонецЕсли;
	
	Возврат НСтр("ru = 'Сервис DSS'") + ": " + ТекстОшибки;
	
КонецФункции

#КонецОбласти

#Область ДиагностикаЭлектроннойПодписи

// Формирует архив, содержащий техническую информацию, и предлагает сохранить его на компьютер.
//
// Параметры:
//   Причина              - Строка - причина сбора технической информации.
//   ОбработчикЗавершения - Неопределено
//                        - ОписаниеОповещения - содержит описание процедуры, которая будет вызвана
//                            после сохранения архива на компьютер со следующими параметрами:
//        АрхивСохранен           - Булево - результат сохранения архива на компьютер.
//        ДополнительныеПараметры - Произвольный - значение, которое было указано
//                                при создании объекта ОписаниеОповещения.
//   ДополнительныеФайлы - Структура - дополнительные данные, которые необходимо поместить в архив:
//                           * Имя    - Строка - имя файла с расширением.
//                           * Данные - ДвоичныеДанные
//                                    - Строка - данные файла или адрес данных во временном хранилище.
//                       - Массив - массив указанных выше структур.
//
Процедура СформироватьТехническуюИнформацию(Причина,
	ОбработчикЗавершения = Неопределено,
	ДополнительныеФайлы = Неопределено) Экспорт
	
	СопроводительныйТекст = СокрЛ(СокрП(Причина) + Символы.ПС + Символы.ПС)
		+ НСтр("ru = 'Информация о компьютере:'") + Символы.ПС + Символы.ПС
		+ ДиагностическаяИнформацияОКомпьютере() + Символы.ПС;
	
	Контекст = Новый Структура;
	Контекст.Вставить("ДополнительныеФайлы", ДополнительныеФайлы);
	Контекст.Вставить("ОбработчикЗавершения", ОбработчикЗавершения);
	Контекст.Вставить("СопроводительныйТекст", СопроводительныйТекст);
	
	ПолучитьВерсиюКомпоненты(
		Новый ОписаниеОповещения("ПослеСбораТехническойИнформацииОКомпоненте", ЭтотОбъект, Контекст));
	
КонецПроцедуры

Функция ДиагностическаяИнформацияОКомпьютере()
	
	Возврат НСтр("ru = 'Клиент:'") + Символы.ПС
		+ ЭлектроннаяПодписьСлужебныйКлиентСервер.ДиагностическаяИнформацияОКомпьютере(Истина);
	
КонецФункции

Асинх Процедура ДиагностическаяИнформацияОПрограммахОпределенныхАвтоматически(Оповещение)
	
	ИспользуемыеПрограммыРезультат = Ждать УстановленныеКриптопровайдеры(, Ложь);
	
	Если Не ИспользуемыеПрограммыРезультат.ПроверкаВыполнена Тогда
		ВыполнитьОбработкуОповещения(Оповещение, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось автоматически определить программы на клиенте: %1'"),
			ИспользуемыеПрограммыРезультат.Ошибка));
		Возврат;
	КонецЕсли;	
	
	Если ИспользуемыеПрограммыРезультат.Криптопровайдеры.Количество() = 0 Тогда
		ВыполнитьОбработкуОповещения(Оповещение, НСтр("ru = 'Нет программ на клиенте, определенных автоматически'"));
		Возврат;
	КонецЕсли;
	
	Заголовок = Символы.ПС + НСтр("ru = 'Автоматически определенные программы на клиенте:'") + Символы.ПС;
	
	Контекст = Новый Структура;
	Контекст.Вставить("Индекс", 0);
	Контекст.Вставить("Оповещение", Оповещение);
	Контекст.Вставить("ИспользуемыеПрограммы", ИспользуемыеПрограммыРезультат.Криптопровайдеры);
	Контекст.Вставить("ДиагностическаяИнформация", Заголовок);
	
	ИнформацияОПрограммахЦиклНачало(Контекст);
	
КонецПроцедуры

Процедура ДиагностическаяИнформацияОПрограммах(Оповещение)
	
	ИспользуемыеПрограммы = ЭлектроннаяПодписьСлужебныйВызовСервера.ИспользуемыеПрограммы();
	Если ИспользуемыеПрограммы.Количество() = 0 Тогда
		ВыполнитьОбработкуОповещения(Оповещение, "");
		Возврат;
	КонецЕсли;
	Заголовок = Символы.ПС + НСтр("ru = 'Программы на клиенте из справочника:'") + Символы.ПС;
	
	Контекст = Новый Структура;
	Контекст.Вставить("Индекс", 0);
	Контекст.Вставить("Оповещение", Оповещение);
	Контекст.Вставить("ИспользуемыеПрограммы", ИспользуемыеПрограммы);
	Контекст.Вставить("ДиагностическаяИнформация", Заголовок);
	
	ИнформацияОПрограммахЦиклНачало(Контекст);
	
КонецПроцедуры

Процедура ИнформацияОПрограммахЦиклНачало(Контекст)
	
	ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
	ПараметрыСоздания.ПоказатьОшибку = Неопределено;
	ПараметрыСоздания.Автоопределение = Ложь;
	ПараметрыСоздания.Программа = Контекст.ИспользуемыеПрограммы[Контекст.Индекс];
	
	Оповещение = Новый ОписаниеОповещения(
		"ИнформацияОПрограммахПослеСозданияМенеджераКриптографии",
		ЭтотОбъект, Контекст);
		
	СоздатьМенеджерКриптографии(Оповещение, "", ПараметрыСоздания);
	
КонецПроцедуры

// Описание
// 
// Параметры:
//   МенеджерКриптографии - МенеджерКриптографии
//   Контекст - Структура:
//   * Индекс - Число
//
Процедура ИнформацияОПрограммахПослеСозданияМенеджераКриптографии(МенеджерКриптографии, Контекст) Экспорт
	
	Контекст.ДиагностическаяИнформация = Контекст.ДиагностическаяИнформация
		+ ЭлектроннаяПодписьСлужебныйКлиентСервер.ДиагностическаяИнформацияПоПрограмме(
			Контекст.ИспользуемыеПрограммы[Контекст.Индекс],
			МенеджерКриптографии,
			МенеджерКриптографии);
	
	Если Контекст.Индекс = Контекст.ИспользуемыеПрограммы.Количество() - 1 Тогда
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Контекст.ДиагностическаяИнформация);
		Возврат;
	КонецЕсли;
	
	Контекст.Индекс = Контекст.Индекс + 1;
	ИнформацияОПрограммахЦиклНачало(Контекст);
	
КонецПроцедуры

Процедура ПослеСбораТехническойИнформацииОКомпоненте(ИнформацияОКомпоненте, Контекст) Экспорт
	
	Контекст.СопроводительныйТекст = Контекст.СопроводительныйТекст + Символы.ПС 
	 + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Версия компоненты %1 на клиенте - %2'"),
		"ExtraCryptoAPI", ИнформацияОКомпоненте) + Символы.ПС;
	
	ДиагностическаяИнформацияОПрограммахОпределенныхАвтоматически(
		Новый ОписаниеОповещения("ПослеСбораТехническойИнформацииОПрограммахОпределенныхАвтоматически",
		ЭтотОбъект, Контекст));
	
КонецПроцедуры

Процедура ПослеСбораТехническойИнформацииОПрограммахОпределенныхАвтоматически(ИнформацияОПрограммах, Контекст) Экспорт

	Контекст.СопроводительныйТекст = Контекст.СопроводительныйТекст + Символы.ПС 
	 + ИнформацияОПрограммах + Символы.ПС;
		
	ДиагностическаяИнформацияОПрограммах(
			Новый ОписаниеОповещения("ПослеСбораТехническойИнформацииОПрограммах", ЭтотОбъект, Контекст));
		
КонецПроцедуры

Процедура ПослеСбораТехническойИнформацииОПрограммах(ИнформацияОПрограммах, Контекст) Экспорт
	
	Контекст.СопроводительныйТекст = Контекст.СопроводительныйТекст + ИнформацияОПрограммах;
	Контекст.Вставить("АдресАрхива", ЭлектроннаяПодписьСлужебныйВызовСервера.АдресАрхиваТехническойИнформации(
		Контекст.СопроводительныйТекст, Контекст.ДополнительныеФайлы, ПроверенныеПутиКМодулямПрограмм()));
	
	ФайловаяСистемаКлиент.СохранитьФайл(Новый ОписаниеОповещения(
		"СформироватьТехническуюИнформациюПослеСохраненияФайла", ЭтотОбъект, Контекст),
		Контекст.АдресАрхива, "service_info.zip");
	
КонецПроцедуры

Процедура СформироватьТехническуюИнформациюПослеСохраненияФайла(СохраненныеФайлы, Контекст) Экспорт
	
	УдалитьИзВременногоХранилища(Контекст.АдресАрхива);
	Если Контекст.ОбработчикЗавершения <> Неопределено Тогда
		ВыполнитьОбработкуОповещения(Контекст.ОбработчикЗавершения, СохраненныеФайлы <> Неопределено);
	КонецЕсли;
	
КонецПроцедуры

Процедура ПолучитьВерсиюКомпоненты(Оповещение)
	
	ПараметрыПодключения = ОбщегоНазначенияКлиент.ПараметрыПодключенияКомпоненты();
	ПараметрыПодключения.ТекстПояснения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Для получения версии требуется установка компоненты %1'"), "ExtraCryptoAPI");
	ПараметрыПодключения.ПредложитьЗагрузить = Ложь;
	ПараметрыПодключения.ПредложитьУстановить = Ложь;
	
	ОписаниеКомпоненты = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОписаниеКомпоненты();
	
	ОбщегоНазначенияКлиент.ПодключитьКомпонентуИзМакета(
		Новый ОписаниеОповещения("ПолучитьВерсиюПослеПодключенияКомпоненты", ЭтотОбъект, Оповещение),
		ОписаниеКомпоненты.ИмяОбъекта,
		ОписаниеКомпоненты.ПолноеИмяМакета,
		ПараметрыПодключения);
	
КонецПроцедуры

// Продолжение процедуры ПолучитьВерсиюКомпоненты.
Процедура ПолучитьВерсиюПослеПодключенияКомпоненты(Результат, Оповещение) Экспорт
	
	ВерсияКомпоненты = "";
	
	Если Результат.Подключено Тогда
		Попытка 
			ОповещениеПослеПолученияВерсии = Новый ОписаниеОповещения("ПослеПолученияВерсииКомпоненты", ЭтотОбъект, Оповещение);
			Результат.ПодключаемыйМодуль.НачатьВызовПолучитьВерсию(ОповещениеПослеПолученияВерсии);
			Возврат;
		Исключение
			ВерсияКомпоненты = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось определить версию компоненты. %1'"), ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
		КонецПопытки;
	Иначе
		Если ПустаяСтрока(Результат.ОписаниеОшибки) Тогда 
			// Пользователь отказался от установки.
			ВерсияКомпоненты = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Компонента %1 не установлена.'"), "ExtraCryptoAPI");
		Иначе 
			// Установка не удалась, описание ошибки в Результат.ОписаниеОшибки.
			ВерсияКомпоненты = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Компонента %1 не установлена (%2).'"), "ExtraCryptoAPI", Результат.ОписаниеОшибки);
		КонецЕсли;
	КонецЕсли;
	
	ВыполнитьОбработкуОповещения(Оповещение, ВерсияКомпоненты);
	
КонецПроцедуры

Процедура ПослеПолученияВерсииКомпоненты(ВерсияКомпоненты, Параметры, Оповещение) Экспорт

	ВыполнитьОбработкуОповещения(Оповещение, ВерсияКомпоненты);
	
КонецПроцедуры

Процедура ВыполнитьПослеПроверкиРасширенияИКомпоненты(Оповещение, Параметры = Неопределено)
	
	Контекст = Новый Структура;
	Контекст.Вставить("УстанавливатьРасширение", Истина);
	Контекст.Вставить("УстанавливатьКомпоненту", Истина);
	Контекст.Вставить("ТекстПояснения");
	
	Если ТипЗнч(Параметры) = Тип("Структура") Тогда
		ЗаполнитьЗначенияСвойств(Контекст, Параметры);
	КонецЕсли;
	
	Если Контекст.ТекстПояснения = Неопределено Тогда
		Контекст.ТекстПояснения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Для выполнения требуется установка компоненты %1'"), "ExtraCryptoAPI")
	КонецЕсли;
		
	Контекст.Вставить("Оповещение", Оповещение);
		
	НачатьПодключениеРасширенияРаботыСКриптографией(Новый ОписаниеОповещения(
		"ВыполнитьПослеПодключенияРасширенияРаботыСКриптографией", ЭтотОбъект, Контекст));

КонецПроцедуры

Процедура ВыполнитьПослеПодключенияРасширенияРаботыСКриптографией(Подключено, Контекст) Экспорт
	
	Если Не Подключено Тогда
		Если Контекст.УстанавливатьРасширение Тогда
			ЭлектроннаяПодписьКлиент.УстановитьРасширение(Истина,
				Новый ОписаниеОповещения("ВыполнитьПослеУстановкиРасширения", ЭтотОбъект, Контекст));
			Возврат;
		Иначе
			ПродолжатьБезУстановкиРасширения = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(
				Контекст, "ПродолжатьБезУстановкиРасширения", Ложь);
			ВыполнитьПослеУстановкиРасширения(ПродолжатьБезУстановкиРасширения, Контекст);
			Возврат;
		КонецЕсли;
	КонецЕсли;
	
	ВыполнитьПослеУстановкиРасширения(Истина, Контекст);
	
КонецПроцедуры

Процедура ВыполнитьПослеУстановкиРасширения(Установлено, Контекст) Экспорт
	
	Если Не Установлено Тогда
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, ТекстОшибкиНеУстановленоРасширение());
		Возврат;
	КонецЕсли;
	
	Если Не ОбщегоНазначенияКлиент.ЭтоWindowsКлиент()
	   И Не ОбщегоНазначенияКлиент.ЭтоLinuxКлиент()
	   И Не ОбщегоНазначенияКлиент.ЭтоMacOSКлиент() Тогда
		
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, ТекстОшибкиУстройствоНеПоддерживается());
		Возврат;
	КонецЕсли;
	
	ПараметрыПодключения = ОбщегоНазначенияКлиент.ПараметрыПодключенияКомпоненты();
	ПараметрыПодключения.ТекстПояснения = Контекст.ТекстПояснения;
	ПараметрыПодключения.ПредложитьУстановить = Контекст.УстанавливатьКомпоненту;
	ПараметрыПодключения.ПредложитьЗагрузить = Контекст.УстанавливатьКомпоненту;
	ОписаниеКомпоненты = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОписаниеКомпоненты();
	ОбщегоНазначенияКлиент.ПодключитьКомпонентуИзМакета(
		Новый ОписаниеОповещения("ВыполнитьПослеПодключенияКомпоненты",
			ЭтотОбъект, Контекст),
		ОписаниеКомпоненты.ИмяОбъекта, ОписаниеКомпоненты.ПолноеИмяМакета, ПараметрыПодключения);
	
КонецПроцедуры

Функция ТекстОшибкиНеУстановленоРасширение()
	
	Возврат НСтр("ru = 'Не установлено расширение для работы с криптографией.'");
	
КонецФункции

Функция ТекстОшибкиУстройствоНеПоддерживается()

	Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Действие доступно только на компьютерах с операционной системой %1, %2 или %3.'"),
					"MacOS", "Windows", "Linux");
КонецФункции

Процедура ВыполнитьПослеПодключенияКомпоненты(Результат, Контекст) Экспорт
	
	Если Результат.Подключено Тогда
		
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат.ПодключаемыйМодуль);
		
	Иначе

		Если ПустаяСтрока(Результат.ОписаниеОшибки) Тогда 
				
			// Пользователь отказался от установки.
			ВыполнитьОбработкуОповещения(Контекст.Оповещение, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Операция невозможна. Требуется установка компоненты %1.'"), "ExtraCryptoAPI"));

		Иначе
				
			// Установка не удалась, описание ошибки в Результат.ОписаниеОшибки.
			ВыполнитьОбработкуОповещения(Контекст.Оповещение, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Операция невозможна. %1'"), Результат.ОписаниеОшибки));

		КонецЕсли;

	КонецЕсли;
	
КонецПроцедуры

Процедура ОповеститьОбУспешномПодключенииКомпоненты(Результат, Контекст) Экспорт
	
	Если ТипЗнч(Результат) = Тип("Строка") Тогда
		ПоказатьПредупреждение(, Результат);
		Возврат;
	КонецЕсли;
	
	ОчиститьКэшУстановленныхКриптопровайдеров();
	Оповестить("Установка_КомпонентаExtraCryptoAPI");
	
КонецПроцедуры

Асинх Функция ПолучитьСвойстваСертификатаАсинх(Сертификат, ОбъектКомпоненты)
		
	СертификатBase64Строка = Ждать СертификатBase64Строка(Сертификат);
	
	Результат = Новый Структура("Ошибка, СвойстваСертификата, СертификатBase64Строка", "");
	Результат.СертификатBase64Строка = СертификатBase64Строка;
	
	Попытка
		
		Ждать ОбъектКомпоненты.ПолучитьСписокОшибокАсинх();
		СвойстваСертификатаРезультат = Ждать ОбъектКомпоненты.ПолучитьСвойстваСертификатаАсинх(СертификатBase64Строка);
		
		Ошибка = Ждать ОбъектКомпоненты.ПолучитьСписокОшибокАсинх();
		Если ЗначениеЗаполнено(Ошибка) Тогда
			ВызватьИсключение Ошибка;
		КонецЕсли;
		
		СвойстваСертификата = ЭлектроннаяПодписьСлужебныйКлиентСервер.СвойстваСертификатаИзОтветаКомпоненты(
			СвойстваСертификатаРезультат.Значение);
	
		Результат.СвойстваСертификата = СвойстваСертификата;
		
	Исключение
		
		Результат.Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Ошибка при получении расширенных свойств сертификата:
			| %1'"),
			ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
		Возврат Результат;
		
	КонецПопытки;
	
	Возврат Результат;
	
КонецФункции

// Сертификат base64 строка.
// 
// Параметры:
//  Сертификат - ДвоичныеДанные
//             - Строка - адрес во временном хранилище
//             - Строка - Сертификат base64 строка
//             - СертификатКриптографии
// 
// Возвращаемое значение:
//  Обещание - Сертификат base64 строка
//
Асинх Функция СертификатBase64Строка(Сертификат)
	
	Если ТипЗнч(Сертификат) = Тип("Строка") И ЭтоАдресВременногоХранилища(Сертификат) Тогда
		Сертификат = ПолучитьИзВременногоХранилища(Сертификат);
	КонецЕсли;

	Если ТипЗнч(Сертификат) = Тип("Строка") Тогда
		Возврат Сертификат;
	КонецЕсли;
	
	Если ТипЗнч(Сертификат) = Тип("СертификатКриптографии") Тогда
		Сертификат = Ждать Сертификат.ВыгрузитьАсинх();
	КонецЕсли;
	
	Сертификат = Base64Строка(Сертификат);
	Сертификат = СтрЗаменить(Сертификат, Символы.ВК, "");
	Сертификат = СтрЗаменить(Сертификат, Символы.ПС, "");

	Возврат Сертификат;
	
КонецФункции

#Область УстановкаСпискаОтзыва

Асинх Процедура УстановитьСписокОтзываСертификатаПослеПодключенияКомпоненты(ОбъектКомпоненты, Контекст) Экспорт
	
	Если ТипЗнч(ОбъектКомпоненты) = Тип("Строка") Тогда
		ОбработатьОшибкуУстановкиСпискаОтзыва(ОбъектКомпоненты, Контекст);
		Возврат;
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(Контекст.Адреса) Тогда
		СвойстваСертификатаРасширенные = Ждать ПолучитьСвойстваСертификатаАсинх(Контекст.Сертификат, ОбъектКомпоненты);
		
		Если ЗначениеЗаполнено(СвойстваСертификатаРасширенные.Ошибка) Тогда
			ОбработатьОшибкуУстановкиСпискаОтзыва(СвойстваСертификатаРасширенные.Ошибка, Контекст);
			Возврат;
		КонецЕсли;
		
		АдресаСписковОтзыва = СвойстваСертификатаРасширенные.СвойстваСертификата.АдресаСписковОтзыва;
		Если АдресаСписковОтзыва.Количество() = 0 Тогда
			ОбработатьОшибкуУстановкиСпискаОтзыва(НСтр("ru = 'В сертификате не указаны адреса списков отзыва.'"),
				Контекст);
			Возврат;
		КонецЕсли;
	Иначе
		Если ТипЗнч(Контекст.Адреса) = Тип("Строка") Тогда
			АдресаСписковОтзыва = СтрРазделить(Контекст.Адреса, ";");
		КонецЕсли;
	КонецЕсли;
	
	Параметры = Новый Структура("АдресРесурса, НаименованиеОперации, АдресВнутренний");
	Параметры.АдресРесурса = АдресаСписковОтзыва;
	Параметры.АдресВнутренний = Контекст.АдресВнутренний;
	Параметры.НаименованиеОперации = НСтр("ru = 'Загрузка списка отзыва сертификата'");
		
	Контекст.Вставить("ОбъектКомпоненты", ОбъектКомпоненты);
	Контекст.Вставить("АдресРесурса", Параметры.АдресРесурса);
	
	ДлительнаяОперация = ЭлектроннаяПодписьСлужебныйВызовСервера.НачатьСкачиваниеФайлаНаСервере(Параметры);
	
	Если Не ДлительнаяОперация.Свойство("АдресРезультата") Тогда
		ПродолжитьУстановкуСпискаОтзываПослеСкачивания(ДлительнаяОперация, Контекст);
		Возврат;
	КонецЕсли;
	
	ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(Неопределено);
	ПараметрыОжидания.Заголовок = Параметры.НаименованиеОперации;
	ПараметрыОжидания.ВыводитьОкноОжидания = Истина;
	
	ОповещениеОЗавершении = Новый ОписаниеОповещения("ПродолжитьУстановкуСпискаОтзываПослеСкачивания",
		ЭтотОбъект, Контекст);
		
	ДлительныеОперацииКлиент.ОжидатьЗавершение(ДлительнаяОперация, ОповещениеОЗавершении, ПараметрыОжидания);
	
КонецПроцедуры

Процедура ПродолжитьУстановкуСпискаОтзываПослеСкачивания(РезультатВыполнения, Контекст) Экспорт
	
	Если РезультатВыполнения = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Если РезультатВыполнения.Статус = "Ошибка" Тогда
		ОбработатьОшибкуУстановкиСпискаОтзыва(РезультатВыполнения.КраткоеПредставлениеОшибки, Контекст);
		Возврат;
	КонецЕсли;
	
	// Результат выполнения фонового задания.
	Попытка
		Результат = ПолучитьИзВременногоХранилища(РезультатВыполнения.АдресРезультата);
	Исключение
		ТекстОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
		ОбработатьОшибкуУстановкиСпискаОтзыва(ТекстОшибки, Контекст);
		Возврат;
	КонецПопытки;
	
	УдалитьИзВременногоХранилища(РезультатВыполнения.АдресРезультата);
	
	Если ЗначениеЗаполнено(Результат.СообщениеОбОшибке) И Не ЗначениеЗаполнено(Результат.ДанныеФайла) Тогда
		ОбработатьОшибкуУстановкиСпискаОтзыва(Результат.СообщениеОбОшибке, Контекст);
		Возврат;
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(Результат.ДанныеФайла) Тогда
		ОбработатьОшибкуУстановкиСпискаОтзыва(
			НСтр("ru = 'Не удалось загрузить список отзыва. Подробнее см. в журнале регистрации.'"), Контекст);
		Возврат;
	КонецЕсли;
	
	ОбщегоНазначенияКлиентСервер.ДополнитьСтруктуру(Результат, Контекст);
	
	ФайловаяСистемаКлиент.СоздатьВременныйКаталог(
		Новый ОписаниеОповещения("УстановитьСписокОтзываПослеСозданияВременногоКаталога", ЭтотОбъект, Результат));
		
КонецПроцедуры

// Установить список отзыва после создания временного каталога.
// 
// Параметры:
//  ИмяВременногоКаталога - Строка
//  Контекст - Структура:
//               * ИмяФайла - Строка
//               * ДанныеФайла - ДвоичныеДанные
//
Асинх Процедура УстановитьСписокОтзываПослеСозданияВременногоКаталога(ИмяВременногоКаталога, Контекст) Экспорт
	
	Если Не ЗначениеЗаполнено(ИмяВременногоКаталога) Тогда
		ОбработатьОшибкуУстановкиСпискаОтзыва(
			НСтр("ru = 'Не удалось создать временный каталог для загрузки списка отзыва.'"), Контекст);
		Возврат;
	КонецЕсли;
	
	ИмяФайлаСпискаОтзыва = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(ИмяВременногоКаталога)
	 + Контекст.ИмяФайла;
	Ждать Контекст.ДанныеФайла.ЗаписатьАсинх(ИмяФайлаСпискаОтзыва);
	
	Контекст.Вставить("ИмяФайлаСпискаОтзыва", ИмяФайлаСпискаОтзыва);
	Контекст.Вставить("ИмяВременногоКаталога", ИмяВременногоКаталога);

	ИмяХранилища = "CA";
	РезультатУстановки = Ждать Контекст.ОбъектКомпоненты.ИмпортироватьСписокОтзываСертификатовАсинх(
		Контекст.ИмяФайлаСпискаОтзыва, ИмяХранилища);
	
	Если РезультатУстановки.Значение <> Истина Тогда
		
		Ошибка = Ждать Контекст.ОбъектКомпоненты.ПолучитьСписокОшибокАсинх();
		Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось установить список отзыва в хранилище ""%1"" по причине:
				 | %2'"), ИмяХранилища, Ошибка);
		ОбработатьОшибкуУстановкиСпискаОтзыва(Ошибка, Контекст);
		
	Иначе
		
		Сообщение = НСтр("ru = 'Установка списка отзыва выполнена успешно.'");

		Если Контекст.ОповещениеОЗавершении <> Неопределено Тогда
			Результат = РезультатУстановкиСертификата();
			Результат.УстановкаВыполнена = Истина;
			Результат.Сообщение = Сообщение;
			ВыполнитьОбработкуОповещения(Контекст.ОповещениеОЗавершении, Результат);
		Иначе
			ПоказатьПредупреждение(, Сообщение);
		КонецЕсли;
		
	КонецЕсли;
	
	Ждать УдалитьФайлыАсинх(Контекст.ИмяВременногоКаталога);
	
КонецПроцедуры

Процедура ОбработатьОшибкуУстановкиСпискаОтзыва(Ошибка, Контекст)
	
	АдресРесурса = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Контекст, "АдресРесурса", Неопределено);
	
	Если ЗначениеЗаполнено(АдресРесурса) Тогда
		Ошибка = Ошибка + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Загрузите вручную и установите список отзыва с:
			|%1'"), СтрСоединить(АдресРесурса, Символы.ПС));
	КонецЕсли;
	
	Если Контекст.ОповещениеОЗавершении <> Неопределено Тогда
		
		Результат = РезультатУстановкиСертификата();
		Результат.Сообщение = Ошибка;
		ВыполнитьОбработкуОповещения(Контекст.ОповещениеОЗавершении, Результат);
		
	Иначе
		
		ПараметрыФормы = Новый Структура;
		ПараметрыФормы.Вставить("ЗаголовокПредупреждения", НСтр("ru = 'Не удалось установить список отзыва.'"));
		ПараметрыФормы.Вставить("ТекстОшибкиКлиент", Ошибка);
		
		ОткрытьФорму("ОбщаяФорма.РасширенноеПредставлениеОшибки",
			ПараметрыФормы, Контекст.Форма,,,,, РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);
			
	КонецЕсли;

КонецПроцедуры

#КонецОбласти

#Область УстановкаСертификата

// Установить корневой сертификат после подключения компоненты.
// 
// Параметры:
//  ОбъектКомпоненты - ОбъектВнешнейКомпоненты  - экземпляр объекта внешней компоненты
//  ПараметрыУстановки - см. ПараметрыУстановкиСертификата
//
Асинх Процедура УстановитьКорневойСертификатПослеПодключенияКомпоненты(ОбъектКомпоненты, ПараметрыУстановки) Экспорт
	
	Если ТипЗнч(ОбъектКомпоненты) = Тип("Строка") Тогда
		ОбработатьОшибкуУстановкиСертификата(ОбъектКомпоненты, ПараметрыУстановки);
		Возврат;
	КонецЕсли;
	
	Результат = Ждать ЦепочкаСертификатовАсинх(ПараметрыУстановки.Сертификат, ОбъектКомпоненты);
		
	Если ЗначениеЗаполнено(Результат.Ошибка) Тогда
		ОбработатьОшибкуУстановкиСертификата(Результат.Ошибка, ПараметрыУстановки);
		Возврат;
	КонецЕсли;
	
	Если Результат.Сертификаты.Количество() = 0 Тогда
		ОбработатьОшибкуУстановкиСертификата(НСтр("ru = 'Цепочка сертификатов не содержит сертификатов.'"), ПараметрыУстановки);
		Возврат;
	КонецЕсли;
	
	СписокЗначений = Новый СписокЗначений;
	Если Не ЗначениеЗаполнено(ПараметрыУстановки.Хранилище) Тогда
		СписокЗначений.Добавить("ROOT", НСтр("ru = 'Доверенные корневые сертификаты'"));
	Иначе
		СписокЗначений.Добавить(ПараметрыУстановки.Хранилище.Значение,
			ПараметрыУстановки.Хранилище.Представление);
	КонецЕсли;
	
	Сертификат = Результат.Сертификаты[Результат.Сертификаты.ВГраница()];
	ПараметрыУстановкиСертификата = ПараметрыУстановкиСертификата(Сертификат.ДанныеСертификата);
	ПараметрыУстановкиСертификата.ВариантыУстановки = СписокЗначений;
	УстановитьСертификатПослеПодключенияКомпоненты(ОбъектКомпоненты, ПараметрыУстановкиСертификата);
	
КонецПроцедуры

Процедура УстановитьСертификатПослеПодключенияКомпоненты(ОбъектКомпоненты, ПараметрыУстановкиСертификата) Экспорт
	
	Если ТипЗнч(ОбъектКомпоненты) = Тип("Строка") Тогда
		ОбработатьОшибкуУстановкиСертификата(ОбъектКомпоненты, ПараметрыУстановкиСертификата);
		Возврат;
	КонецЕсли;
	
	Если ПараметрыУстановкиСертификата.ВариантыУстановки = Неопределено
		Или ТипЗнч(ПараметрыУстановкиСертификата.ВариантыУстановки) = Тип("СписокЗначений")
		Или ПараметрыУстановкиСертификата.ВариантыУстановки = "Контейнер"
		И ПараметрыУстановкиСертификата.СвойстваКонтейнера = Неопределено Тогда
		
		ПараметрыФормы = Новый Структура;
		ПараметрыФормы.Вставить("Сертификат", ПараметрыУстановкиСертификата.Сертификат);
		ПараметрыФормы.Вставить("ВариантыУстановки", ПараметрыУстановкиСертификата.ВариантыУстановки);
		
		ОповещениеОЗакрытииФормы = Новый ОписаниеОповещения("ВыполнитьПослеУстановкиСертификата",
			ЭтотОбъект, ПараметрыУстановкиСертификата);
		
		ОткрытьФорму("Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования.Форма.УстановкаСертификата",
			ПараметрыУстановкиСертификата, ПараметрыУстановкиСертификата.Форма,,,,
			ОповещениеОЗакрытииФормы, РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);
		Возврат;
	КонецЕсли;

	УстановитьСертификатПослеВыбораВариантаУстановки(ПараметрыУстановкиСертификата, ОбъектКомпоненты);
	
КонецПроцедуры

Асинх Процедура УстановитьСертификатПослеВыбораВариантаУстановки(ПараметрыУстановкиСертификата, ОбъектКомпоненты = Неопределено) Экспорт
		
	Хранилище = ПараметрыУстановкиСертификата.Хранилище;
	ПредставлениеХранилища = "";
	Если ТипЗнч(Хранилище) = Тип("Структура") Тогда
		Хранилище = ПараметрыУстановкиСертификата.Хранилище.Значение;
		ПредставлениеХранилища = ПараметрыУстановкиСертификата.Хранилище.Представление;
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(ПредставлениеХранилища) Тогда
		ПредставлениеХранилища = Хранилище;
	КонецЕсли;
	
	СертификатСтрокой = Ждать СертификатBase64Строка(ПараметрыУстановкиСертификата.Сертификат);
	Если ОбъектКомпоненты = Неопределено Тогда
		Попытка
			ОбъектКомпоненты = Ждать ОбъектВнешнейКомпонентыExtraCryptoAPI();
		Исключение
			Ошибка = ТекстОшибкиНеУстановленаКомпонента();
			ОбработатьОшибкуУстановкиСертификата(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Не удалось установить сертификат в %1.
					|%2'"), ПредставлениеХранилища, Ошибка), ПараметрыУстановкиСертификата);
		КонецПопытки
	КонецЕсли;
	
	Ждать ОбъектКомпоненты.ПолучитьСписокОшибокАсинх();

	Если ЗначениеЗаполнено(ПараметрыУстановкиСертификата.СвойстваКонтейнера) Тогда
		
		СвойстваКонтейнера = ПараметрыУстановкиСертификата.СвойстваКонтейнера;
		Результат = Ждать ОбъектКомпоненты.УстановитьСвязьСКонтейнеромАсинх(
			СвойстваКонтейнера.ТипПрограммы, СвойстваКонтейнера.ИмяПрограммы, СвойстваКонтейнера.Имя, СертификатСтрокой);
		Если Результат.Значение <> Истина Тогда
			Ошибка = Ждать ОбъектКомпоненты.ПолучитьСписокОшибокАсинх();
			ОбработатьОшибкуУстановкиСертификата(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Не удалось связать сертификат с контейнером %1.
						|%2'"), СвойстваКонтейнера.Имя, Ошибка), ПараметрыУстановкиСертификата);
			Возврат;
		КонецЕсли;
		
		ПредставлениеХранилища = СвойстваКонтейнера.Имя;
		
	Иначе
		
		Результат = Ждать ОбъектКомпоненты.УстановитьСертификатВХранилищеАсинх(СертификатСтрокой, Хранилище);
	
		Если Результат.Значение <> Истина Тогда
			Ошибка = Ждать ОбъектКомпоненты.ПолучитьСписокОшибокАсинх();
			ОбработатьОшибкуУстановкиСертификата(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Не удалось установить сертификат в %1.
						|%2'"), ПредставлениеХранилища, Ошибка), ПараметрыУстановкиСертификата);
			Возврат;
		КонецЕсли;
		
	КонецЕсли;
	
	Результат = РезультатУстановкиСертификата();
	Результат.УстановкаВыполнена = Истина;
	Результат.Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Сертификат успешно установлен в %1.'"), ПредставлениеХранилища);
	
	ВыполнитьПослеУстановкиСертификата(Результат,
		Новый Структура("ОповещениеОЗавершении", ПараметрыУстановкиСертификата.ОповещениеОЗавершении));
		
КонецПроцедуры

Процедура ОбработатьОшибкуУстановкиСертификата(Ошибка, Контекст)
	
	Если Контекст.ОповещениеОЗавершении <> Неопределено Тогда
		
		Результат = РезультатУстановкиСертификата();
		Результат.Сообщение = Ошибка;
		ВыполнитьОбработкуОповещения(Контекст.ОповещениеОЗавершении, Результат);
		
	Иначе
		
		ПараметрыФормы = Новый Структура;
		ПараметрыФормы.Вставить("ЗаголовокПредупреждения", НСтр("ru = 'Не удалось установить сертификат.'"));
		ПараметрыФормы.Вставить("ТекстОшибкиКлиент", Ошибка);
		
		ОткрытьФорму("ОбщаяФорма.РасширенноеПредставлениеОшибки",
			ПараметрыФормы, Контекст.Форма,,,,, РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);
			
	КонецЕсли;

КонецПроцедуры

Процедура ВыполнитьПослеУстановкиСертификата(Результат, Контекст) Экспорт
	
	Если Результат = Неопределено Тогда
		Результат = РезультатУстановкиСертификата();
		Результат.УстановкаВыполнена = Ложь;
		Результат.Сообщение = НСтр("ru = 'Установка сертификата не выполнена.'");
	КонецЕсли;
	
	Если Контекст.ОповещениеОЗавершении <> Неопределено Тогда
		ВыполнитьОбработкуОповещения(Контекст.ОповещениеОЗавершении, Результат);
	Иначе
		ПоказатьПредупреждение(, Результат.Сообщение);
	КонецЕсли;
	
КонецПроцедуры

Функция РезультатУстановкиСертификата()
	
	Возврат Новый Структура("УстановкаВыполнена, Сообщение", Ложь, "");
	
КонецФункции

#КонецОбласти

#Область ПолучениеЦепочкиСертификатов

// Получает из сертификата цепочку корневых сертификатов
//
Процедура ПолучитьЦепочкуСертификатов(Оповещение, Сертификат, ИдентификаторФормы = Неопределено) Экспорт
	
	Контекст = Новый Структура;
	Контекст.Вставить("Оповещение", Оповещение);
	Контекст.Вставить("Сертификат", Сертификат);
	Контекст.Вставить("ИдентификаторФормы", ИдентификаторФормы);
		
	Оповещение = Новый ОписаниеОповещения("ПолучитьЦепочкуСертификатовПослеПодключенияКомпоненты",
		ЭтотОбъект, Контекст);
	ВыполнитьПослеПроверкиРасширенияИКомпоненты(Оповещение);
	
КонецПроцедуры

Асинх Процедура ПолучитьЦепочкуСертификатовПослеПодключенияКомпоненты(ОбъектКомпоненты, Контекст) Экспорт
	
	Результат = Новый Структура("Сертификаты, Ошибка", Новый Массив, "");
	
	Если ТипЗнч(ОбъектКомпоненты) = Тип("Строка") Тогда
		Результат.Ошибка = ОбъектКомпоненты;
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
		Возврат;
	КонецЕсли;
	
	Результат = Ждать ЦепочкаСертификатовАсинх(Контекст.Сертификат, ОбъектКомпоненты, Контекст.ИдентификаторФормы);
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
	
КонецПроцедуры

Асинх Функция ЦепочкаСертификатовАсинх(Сертификат, ОбъектКомпоненты = Неопределено, ИдентификаторФормы = Неопределено)
	
	Результат = Новый Структура("Сертификаты, Ошибка", Новый Массив, "");
	Сертификат = Ждать СертификатBase64Строка(Сертификат);
	
	Если ОбъектКомпоненты = Неопределено Тогда
		Попытка
			ОбъектКомпоненты = Ждать ОбъектВнешнейКомпонентыExtraCryptoAPI(Истина);
		Исключение
			Результат.Ошибка = ТекстОшибкиНеУстановленаКомпонента();
			Возврат Результат;
		КонецПопытки;
	КонецЕсли;
	
	Попытка
		Ждать ОбъектКомпоненты.ПолучитьСписокОшибокАсинх();
		СертификатыРезультат = Ждать ОбъектКомпоненты.ПолучитьЦепочкуСертификатовАсинх(Сертификат);
		
		Ошибка = Ждать ОбъектКомпоненты.ПолучитьСписокОшибокАсинх();
		Если ЗначениеЗаполнено(Ошибка) Тогда
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось получить цепочку сертификатов на компьютере: %1'"),
				Ошибка); 
		КонецЕсли;
			
		Если СертификатыРезультат = Неопределено Тогда
			ВызватьИсключение НСтр("ru = 'Не удалось получить цепочку сертификатов.'");
		КонецЕсли;
		
		Результат = ЭлектроннаяПодписьСлужебныйКлиентСервер.ЦепочкаСертификатовИзОтветаКомпоненты(
			СертификатыРезультат.Значение, ИдентификаторФормы);

	Исключение
		Результат.Вставить("Ошибка", ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
		Возврат Результат;
	КонецПопытки;
	
	Возврат Результат;
	
КонецФункции

#КонецОбласти

#Область УстановкаИПроверкаПрограммКриптографии

// Результат получения установленных криптопровайдеров.
// 
// Возвращаемое значение:
//  Структура - результат получения установленных криптопровайдеров:
//   * ПроверкаВыполнена - Булево
//   * КомпонентаУстановлена - Булево
//   * РасширениеУстановлено - Булево
//   * Криптопровайдеры - Массив
//   * КриптопровайдерыНаСервере - Массив
//   * Ошибка - Строка
//
Функция РезультатПолученияУстановленныхКриптопровайдеров()
	
	Результат = Новый Структура;
	Результат.Вставить("ПроверкаВыполнена",         Ложь);
	Результат.Вставить("КомпонентаУстановлена",     Ложь);
	Результат.Вставить("Криптопровайдеры",          Новый Массив);
	Результат.Вставить("КриптопровайдерыНаСервере", Новый Массив);
	Результат.Вставить("Ошибка", "");
	Возврат Результат;
	
КонецФункции

// Продолжение процедуры ПолучитьУстановленныеКриптопровайдеры
Асинх Процедура ПолучитьУстановленныеКриптопровайдерыПослеПодключенияКомпоненты(ОбъектКомпоненты, Контекст) Экспорт
	
	Результат = Контекст.Результат;
	
	Если ТипЗнч(ОбъектКомпоненты) = Тип("Строка") Тогда
		Результат.Ошибка = ОбъектКомпоненты;
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
		Возврат;
	КонецЕсли;
	
	Результат.КомпонентаУстановлена = Истина;
	КриптопровайдерыРезультат = Ждать УстановленныеКриптопровайдерыИзКэша(Контекст.УстанавливатьКомпоненту);
	Если КриптопровайдерыРезультат.ПроверкаВыполнена Тогда
		Результат.Криптопровайдеры = КриптопровайдерыРезультат.Криптопровайдеры;
		Результат.ПроверкаВыполнена = Истина;
	Иначе
		Результат.Ошибка = КриптопровайдерыРезультат.Ошибка;
	КонецЕсли;
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);

КонецПроцедуры

Асинх Функция УстановленныеКриптопровайдеры(ОбъектКомпоненты = Неопределено, ПредложитьУстановить = Ложь) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("ПроверкаВыполнена", Ложь);
	Результат.Вставить("Криптопровайдеры", Новый Массив);
	Результат.Вставить("Ошибка", "");
	
	Если ОбъектКомпоненты = Неопределено Тогда
		
		ТекстПояснения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Для получения данных об установленных программах для работы с электронной подписью требуется установка внешней компоненты %1.'"),
			"ExtraCryptoAPI");
		
		Попытка
			ОбъектКомпоненты = Ждать ОбъектВнешнейКомпонентыExtraCryptoAPI(ПредложитьУстановить, ТекстПояснения);
		Исключение
			Результат.Ошибка = ТекстОшибкиНеУстановленаКомпонента();
			Возврат Результат;
		КонецПопытки;
	КонецЕсли;
		
	Попытка
		Ждать ОбъектКомпоненты.ПолучитьСписокОшибокАсинх();
		РезультатСписок = Ждать ОбъектКомпоненты.ПолучитьСписокКриптопровайдеровАсинх();
		
		Ошибка = Ждать ОбъектКомпоненты.ПолучитьСписокОшибокАсинх();
		Если ЗначениеЗаполнено(Ошибка) Тогда
			ВызватьИсключение Ошибка;
		КонецЕсли;
		
		ПрограммыПоИменамСТипом = ЭлектроннаяПодписьКлиент.ОбщиеНастройки().ПрограммыПоИменамСТипом;
		Криптопровайдеры = ЭлектроннаяПодписьСлужебныйКлиентСервер.УстановленныеКриптопровайдерыИзОтветаКомпоненты(
			РезультатСписок.Значение, ПрограммыПоИменамСТипом);
		Результат.ПроверкаВыполнена = Истина;
	Исключение
		Результат.Ошибка = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
		Возврат Результат;
	КонецПопытки;
	
	Результат.Криптопровайдеры = Криптопровайдеры;
	ЗаписатьВКэшУстановленныеКриптопровайдеры(Результат);
	
	Возврат Результат; 
	
КонецФункции

// Возвращает результат проверки криптопровайдеров из кэша с обновлением в 5 минут.
Асинх Функция УстановленныеКриптопровайдерыИзКэша(ПредложитьУстановить = Ложь)
	
	ИмяПараметра = "ЭлектроннаяПодпись.УстановленныеКриптопровайдеры";
	
	Если ПараметрыПриложения[ИмяПараметра] = Неопределено 
		Или ПараметрыПриложения[ИмяПараметра].ВремяПроверки + 300 < ТекущаяДата() // АПК:143 Должна использоваться ТекущаяДата().
		Или ПараметрыПриложения[ИмяПараметра].Ошибка = ТекстОшибкиНеУстановленаКомпонента() И ПредложитьУстановить Тогда
			
		РезультатПроверки = Ждать УстановленныеКриптопровайдеры(Неопределено, ПредложитьУстановить);
		
		Если Не РезультатПроверки.ПроверкаВыполнена Тогда
			ЗаписатьВКэшУстановленныеКриптопровайдеры(РезультатПроверки);
		КонецЕсли;
		
		Возврат РезультатПроверки;
		
	Иначе
		
		РезультатИзКэша = ПараметрыПриложения[ИмяПараметра];
		
		Результат = Новый Структура;
		Результат.Вставить("ПроверкаВыполнена", РезультатИзКэша.ПроверкаВыполнена);
		Результат.Вставить("Криптопровайдеры", Новый Массив(РезультатИзКэша.Криптопровайдеры));
		Результат.Вставить("Ошибка", РезультатИзКэша.Ошибка);
		
		Возврат Результат;
		
	КонецЕсли;
	
КонецФункции

Процедура ОчиститьКэшУстановленныхКриптопровайдеров() Экспорт
	
	ИмяПараметра = "ЭлектроннаяПодпись.УстановленныеКриптопровайдеры";
	
	Если ПараметрыПриложения[ИмяПараметра] <> Неопределено Тогда
		ПараметрыПриложения[ИмяПараметра] = Неопределено;
	КонецЕсли;
	
КонецПроцедуры

Процедура ЗаписатьВКэшУстановленныеКриптопровайдеры(Результат)
	
	РезультатДляКэша = Новый Структура;
	РезультатДляКэша.Вставить("ПроверкаВыполнена", Результат.ПроверкаВыполнена);
	РезультатДляКэша.Вставить("Криптопровайдеры", Новый ФиксированныйМассив(Результат.Криптопровайдеры));
	РезультатДляКэша.Вставить("Ошибка", Результат.Ошибка);
	РезультатДляКэша.Вставить("ВремяПроверки", ТекущаяДата()); // АПК:143 Должна использоваться ТекущаяДата().
	
	ИмяПараметра = "ЭлектроннаяПодпись.УстановленныеКриптопровайдеры";
	ПараметрыПриложения.Вставить(ИмяПараметра, Новый ФиксированнаяСтруктура(РезультатДляКэша));
	
КонецПроцедуры

Функция ТекстОшибкиНеУстановленаКомпонента()
	
	Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не установлена компонента %1'"), "ExtraCryptoAPI");
	
КонецФункции

// Продолжение процедуры ПроверитьУстановкуПрограммКриптографии
Процедура ПроверитьУстановкуПрограммКриптографииПослеПолученияУстановленных(Результат, Контекст) Экспорт
	
	РезультатПроверки = Новый Структура("КомпонентаУстановлена, Ошибка, ПроверкаВыполнена");
	ЗаполнитьЗначенияСвойств(РезультатПроверки, Результат);
	РезультатПроверки.Вставить("Программы", Новый Массив);
	РезультатПроверки.Вставить("ПрограммыНаСервере", Новый Массив);
	РезультатПроверки.Вставить("ВозможенКонфликт", Ложь);
	РезультатПроверки.Вставить("ВозможенКонфликтНаСервере", Ложь);
	
	Если Не РезультатПроверки.ПроверкаВыполнена Тогда
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, РезультатПроверки);
		Возврат;
	КонецЕсли;
	
	ПараметрыОбработки = Новый Структура("АлгоритмыПодписи, ПроверяемыеПрограммы, ТипДанных, РасширенноеОписание");
	ЗаполнитьЗначенияСвойств(ПараметрыОбработки, Контекст);
	ПараметрыОбработки.Вставить("ЭтоСервер", Ложь);
	
	ЕстьПроверяемыеПрограммы = Ложь;
	
	ЭлектроннаяПодписьСлужебныйКлиентСервер.ОбработатьРезультатПроверкиПрограмм(Результат.Криптопровайдеры,
		РезультатПроверки.Программы, РезультатПроверки.ВозможенКонфликт, ПараметрыОбработки, ЕстьПроверяемыеПрограммы);
		
	ПараметрыОбработки.Вставить("ЭтоСервер", Истина);
	ЭлектроннаяПодписьСлужебныйКлиентСервер.ОбработатьРезультатПроверкиПрограмм(Результат.КриптопровайдерыНаСервере,
		РезультатПроверки.ПрограммыНаСервере, РезультатПроверки.ВозможенКонфликтНаСервере, ПараметрыОбработки, ЕстьПроверяемыеПрограммы);
		
	// Локализация
	
	Если Контекст.ПредлагатьУстановитьПрограмму 
		И РезультатПроверки.ПроверкаВыполнена 
		И Не ЕстьПроверяемыеПрограммы
		И Не Контекст.ЭтоПовторнаяПроверка Тогда
		
		Оповещение = Новый ОписаниеОповещения("ПослеУстановкиКриптопровайдера", ЭтотОбъект, Контекст);
		ОткрытьФорму("Обработка.ПрограммыЭлектроннойПодписиИШифрования.Форма.УстановкаПрограммКриптопровайдеров",,
			Контекст.Форма,,,,Оповещение, РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);
			
		Возврат;
	КонецЕсли;
	
	// Конец Локализация
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, РезультатПроверки);

КонецПроцедуры

// Возвращаемое значение:
//  Структура:
//   * ОповещениеОЗавершении - ОписаниеОповещения
//   * Программы  - см. ЭлектроннаяПодписьСлужебныйВызовСервера.ЗаполнитьСписокПрограммДляПоиска
//   * Индекс - Число
//
Функция КонтекстПоискаУстановленныхПрограмм()
	
	Контекст = Новый Структура;
	Контекст.Вставить("Индекс");
	Контекст.Вставить("Программы");
	Контекст.Вставить("ОповещениеОЗавершении");
	
	Возврат Контекст;
	
КонецФункции

// Локализация

#Область УстановкаКриптопровайдеровЛокализация

#Область УстановитьCryptoPRO

Процедура УстановитьКриптоПро(Форма, ОповещениеОЗавершении, ВходящийКонтекст) Экспорт
	
	Если ЗначениеЗаполнено(ВходящийКонтекст) Тогда
		ПослеСохраненияФайловДистрибутива(Истина, ВходящийКонтекст);
		Возврат;
	КонецЕсли;
	
	Если ОбщегоНазначенияКлиент.ЭтоWindowsКлиент() Тогда
		Контекст = Новый Структура;
		Контекст.Вставить("ОповещениеОЗавершении", ОповещениеОЗавершении);
		Контекст.Вставить("ВладелецФормы", Форма.ВладелецФормы);
		Контекст.Вставить("Форма", Форма);
		Контекст.Вставить("ИмяПрограммы", ЭлектроннаяПодписьКлиентСерверЛокализация.ИмяПрограммыКриптоПро());
		Оповещение = Новый ОписаниеОповещения("УстановитьCryptoProCSPПослеВводаРегистрационныхДанных",
			ЭлектроннаяПодписьСлужебныйКлиент, Контекст);
		
		ОткрытьФорму(
			"Обработка.ПрограммыЭлектроннойПодписиИШифрования.Форма.УстановкаCryptoProCSPРегистрационныеДанные",,
			Форма,,,, Оповещение);
	Иначе
		
		ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( 
			НСтр("ru = 'Автоматическая установка %1 возможна только на операционных системах семейства Windows.
			|Вы можете скачать дистрибутив программы с %2 и установить ее самостоятельно.'"),
			ЭлектроннаяПодписьКлиентСерверЛокализация.ИмяПрограммыКриптоПро(),
			"www.cryptopro.ru");
		ОбработатьОшибкуУстановкиПрограммыКриптографии(ОписаниеОшибки, ОповещениеОЗавершении);
		
	КонецЕсли;
		
КонецПроцедуры

Процедура УстановитьCryptoProCSPПослеВводаРегистрационныхДанных(РегистрационныеДанные, ВходящийКонтекст) Экспорт
	
	ОповещениеПослеСозданияКаталога = Новый ОписаниеОповещения(
			"УстановитьКриптопровайдерПослеСозданияВременногоКаталога", ЭтотОбъект, ВходящийКонтекст);
	
	ВходящийКонтекст.Вставить("ПослеСозданияВременногоКаталога", ОповещениеПослеСозданияКаталога);
		
	Если ЗначениеЗаполнено(РегистрационныеДанные) И ТипЗнч(РегистрационныеДанные) = Тип("Структура") Тогда
		
		ВходящийКонтекст.Вставить("РегистрационныеДанные", РегистрационныеДанные);
		Оповещение = Новый ОписаниеОповещения(
			"УстановитьКриптопровайдерПослеПолученияДистрибутива", ЭтотОбъект, ВходящийКонтекст);
		
		ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ВходящийКонтекст.Форма);
		ПараметрыОжидания.ВыводитьОкноОжидания = Истина;
		
		ДлительнаяОперация = ЭлектроннаяПодписьСлужебныйВызовСервера.ПолучитьДистрибутивCryptoProCSP(
			ВходящийКонтекст.РегистрационныеДанные);
		ДлительныеОперацииКлиент.ОжидатьЗавершение(ДлительнаяОперация, Оповещение, ПараметрыОжидания);
	Иначе
		ОбработатьОшибкуУстановкиПрограммыКриптографии(НСтр("ru = 'Пользователь прервал операцию'"), ВходящийКонтекст);
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область УстановитьVipNet

Процедура УстановитьVipNet(Форма, ОповещениеОЗавершении, ВходящийКонтекст) Экспорт
	
	Если ЗначениеЗаполнено(ВходящийКонтекст) Тогда
		ПослеСохраненияФайловДистрибутива(Истина, ВходящийКонтекст);
		Возврат;
	КонецЕсли;
	
	СистемнаяИнформация = Новый СистемнаяИнформация;
	Если СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86
		ИЛИ СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86_64 Тогда
		
		Контекст = Новый Структура;
		Контекст.Вставить("ОповещениеОЗавершении", ОповещениеОЗавершении);
		Контекст.Вставить("ВладелецФормы", Форма.ВладелецФормы);
		Контекст.Вставить("Форма", Форма);
		Контекст.Вставить("ИмяПрограммы", ЭлектроннаяПодписьКлиентСерверЛокализация.ИмяПрограммыVipNet());
		
		Оповещение = Новый ОписаниеОповещения("УстановитьViPNetCSPПослеВводаРегистрационныхДанных",
			ЭлектроннаяПодписьСлужебныйКлиент, Контекст);
		
		ОткрытьФорму(
			"Обработка.ПрограммыЭлектроннойПодписиИШифрования.Форма.УстановкаViPNetCSPРегистрационныеДанные",,
			Форма,,,, Оповещение);
	Иначе
		ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Установка %1 возможна только на операционных системах семейства Windows.'"),
			ЭлектроннаяПодписьКлиентСерверЛокализация.ИмяПрограммыVipNet());
		ОбработатьОшибкуУстановкиПрограммыКриптографии(ОписаниеОшибки, ОповещениеОЗавершении);
	КонецЕсли;
	
КонецПроцедуры

Процедура УстановитьViPNetCSPПослеВводаРегистрационныхДанных(РегистрационныеДанные, ВходящийКонтекст) Экспорт
	
	Если РегистрационныеДанные = КодВозвратаДиалога.Отмена
		 Или РегистрационныеДанные = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	СистемнаяИнформация = Новый СистемнаяИнформация;
	
	Если СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86 Тогда
		РегистрационныеДанные.Вставить("Разрядность", 32);
	ИначеЕсли СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86_64 Тогда
		РегистрационныеДанные.Вставить("Разрядность", 64);
	Иначе
		Возврат;
	КонецЕсли;
	
	ОповещениеПослеСозданияКаталога = Новый ОписаниеОповещения(
			"УстановитьКриптопровайдерПослеСозданияВременногоКаталога", ЭтотОбъект, ВходящийКонтекст);
	
	ВходящийКонтекст.Вставить("ПослеСозданияВременногоКаталога", ОповещениеПослеСозданияКаталога);
	
	Если ЗначениеЗаполнено(РегистрационныеДанные) И ТипЗнч(РегистрационныеДанные) = Тип("Структура") Тогда
		ВходящийКонтекст.Вставить("РегистрационныеДанные", РегистрационныеДанные);
		Оповещение = Новый ОписаниеОповещения(
			"УстановитьКриптопровайдерПослеПолученияДистрибутива", ЭтотОбъект, ВходящийКонтекст);
		
		ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ВходящийКонтекст.Форма);
		ПараметрыОжидания.ВыводитьОкноОжидания = Истина;
		
		ДлительнаяОперация = ЭлектроннаяПодписьСлужебныйВызовСервера.ПолучитьДистрибутивViPNetCSP(ВходящийКонтекст.РегистрационныеДанные);
		ДлительныеОперацииКлиент.ОжидатьЗавершение(ДлительнаяОперация, Оповещение, ПараметрыОжидания);
	Иначе
		ОбработатьОшибкуУстановкиПрограммыКриптографии(НСтр("ru = 'Пользователь прервал операцию'"), ВходящийКонтекст);
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

Процедура УстановитьSignalCOM() Экспорт
	
	ФайловаяСистемаКлиент.ОткрытьНавигационнуюСсылку("https://www.signal-com.ru/products/crypt/signal-com-csp/");
	
КонецПроцедуры

Процедура УстановитьLISSI() Экспорт
	
	ФайловаяСистемаКлиент.ОткрытьНавигационнуюСсылку("http://soft.lissi.ru/ls_product/skzi/");
	
КонецПроцедуры

Процедура УстановитьКриптопровайдерПослеПолученияДистрибутива(ДлительнаяОперация, ВходящийКонтекст) Экспорт
	
	Если ДлительнаяОперация = Неопределено Тогда
		ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Вызов API сервиса выдачи дистрибутивов %1 не был завершен штатно.'"), ВходящийКонтекст.ИмяПрограммы);
		ОбработатьОшибкуУстановкиПрограммыКриптографии(ОписаниеОшибки, ВходящийКонтекст);
		Возврат;
	КонецЕсли;
	
	Если ДлительнаяОперация.Статус = "Выполнено" Тогда
		РезультатПолученияДистрибутива = ЭлектроннаяПодписьСлужебныйВызовСервера.РезультатПолученияДистрибутиваКриптопровайдера(
			ДлительнаяОперация, ВходящийКонтекст.Форма.УникальныйИдентификатор);
		Если ЗначениеЗаполнено(РезультатПолученияДистрибутива.Ошибка) Тогда
			ОбработатьОшибкуУстановкиПрограммыКриптографии(РезультатПолученияДистрибутива.Ошибка, ВходящийКонтекст);
			Возврат;
		КонецЕсли;
		ОбщегоНазначенияКлиентСервер.ДополнитьСтруктуру(ВходящийКонтекст, РезультатПолученияДистрибутива.ДанныеДистрибутива);
		ФайловаяСистемаКлиент.СоздатьВременныйКаталог(ВходящийКонтекст.ПослеСозданияВременногоКаталога);
	Иначе
		ОбработатьОшибкуУстановкиПрограммыКриптографии(НСтр("ru = 'Пользователь прервал операцию'"), ВходящийКонтекст);
		Возврат;
	КонецЕсли;
	
КонецПроцедуры

Процедура УстановитьКриптопровайдерПослеСозданияВременногоКаталога(ИмяКаталогаВременныхФайлов, ВходящийКонтекст) Экспорт
	
	ИмяКаталогаВременныхФайлов = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(ИмяКаталогаВременныхФайлов);
	ВходящийКонтекст.Вставить("ВременныйКаталог", ИмяКаталогаВременныхФайлов);
	
	Оповещение = Новый ОписаниеОповещения("ПослеСохраненияФайловДистрибутива", ЭтотОбъект, ВходящийКонтекст);
	ПараметрыСохранения = ФайловаяСистемаКлиент.ПараметрыСохраненияФайла();
	ПараметрыСохранения.Интерактивно = Ложь;
	ПараметрыСохранения.Диалог.Каталог = ИмяКаталогаВременныхФайлов;
	ФайловаяСистемаКлиент.СохранитьФайлы(Оповещение, ВходящийКонтекст.Дистрибутив, ПараметрыСохранения);
	
КонецПроцедуры

Процедура ПослеСохраненияФайловДистрибутива(ПолученныеФайлы, ВходящийКонтекст) Экспорт
	
	Если ПолученныеФайлы = Неопределено Тогда
		ОбработатьОшибкуУстановкиПрограммыКриптографии(НСтр("ru = 'Не удалось сохранить на компьютер файлы дистрибутива'"),
			ВходящийКонтекст);
		Возврат;
	КонецЕсли;
	
	ВходящийКонтекст.Вставить("ФайлыДистрибутиваПолучены", Истина);
	
	Если ВходящийКонтекст.РегистрационныеДанные.ВыполнятьКонтрольЦелостности Тогда
		ПараметрыФормы = Новый Структура;

		ПараметрыФормы.Вставить("Дистрибутив", ВходящийКонтекст.ВременныйКаталог + ВходящийКонтекст.ИмяФайлаДистрибутива);
		ПараметрыФормы.Вставить("Версия", ВходящийКонтекст.Версия);
		ПараметрыФормы.Вставить("ИмяПрограммы", ВходящийКонтекст.ИмяПрограммы);
		ПараметрыФормы.Вставить("КонтрольнаяСумма", ВходящийКонтекст.КонтрольнаяСумма);
		ПараметрыФормы.Вставить("КомандаЗапуска", ВходящийКонтекст.КомандаЗапуска);

		ОткрытьФорму(
			"Обработка.ПрограммыЭлектроннойПодписиИШифрования.Форма.УстановкаКриптопровайдераИнформацияОДистрибутиве",
			ПараметрыФормы, , , , ,
			Новый ОписаниеОповещения("УстановитьКриптопровайдерПослеПолученияПодтвержденияНаУстановку", ЭтотОбъект,
			ВходящийКонтекст));
	Иначе
		УстановитьКриптопровайдерПослеПолученияПодтвержденияНаУстановку(Истина, ВходящийКонтекст);
	КонецЕсли;
	
КонецПроцедуры

Процедура УстановитьКриптопровайдерПослеПолученияПодтвержденияНаУстановку(Результат, ВходящийКонтекст) Экспорт
	
	Если Результат = Истина Тогда

		ЗапуститьПриложениеНаКлиенте(ВходящийКонтекст.КомандаЗапуска, ВходящийКонтекст.ВременныйКаталог,
			Истина, Ложь, ВходящийКонтекст);
	Иначе
		
		ОбработатьОшибкуУстановкиПрограммыКриптографии(НСтр("ru = 'Пользователь прервал операцию'"), ВходящийКонтекст);
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ОбработатьОшибкуУстановкиПрограммыКриптографии(Ошибка, ВходящийКонтекст)
	
	РезультатВыполнения = Новый Структура("Выполнено", Ложь);
	РезультатВыполнения.Вставить("ОписаниеОшибки", Ошибка);
		
	Если ТипЗнч(ВходящийКонтекст) = Тип("Структура") 
		И ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ВходящийКонтекст,"ФайлыДистрибутиваПолучены", Ложь) Тогда
		РезультатВыполнения.Вставить("ВходящийКонтекст", ВходящийКонтекст);
	КонецЕсли;
	
	Если ТипЗнч(ВходящийКонтекст) = Тип("Структура") И ВходящийКонтекст.ОповещениеОЗавершении <> Неопределено Тогда
			
		ВыполнитьОбработкуОповещения(ВходящийКонтекст.ОповещениеОЗавершении, РезультатВыполнения);
		
	ИначеЕсли ТипЗнч(ВходящийКонтекст) = Тип("ОписаниеОповещения") Тогда
		
		РезультатВыполнения = Новый Структура("Выполнено", Ложь);
		РезультатВыполнения.Вставить("ОписаниеОшибки", Ошибка);
		ВыполнитьОбработкуОповещения(ВходящийКонтекст, РезультатВыполнения);
	
	Иначе
		
		ПоказатьПредупреждение(Неопределено, Ошибка,, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Установка %1'"), ВходящийКонтекст.ИмяПрограммы));
		
	КонецЕсли;
	
КонецПроцедуры

#Область ЗапуститьПриложениеНаКлиенте

Процедура ЗапуститьПриложениеНаКлиенте(СтрокаКоманды, ТекущийКаталог, ДождатьсяЗавершения, ВыводитьСообщения, ВходящийКонтекст)
	
	Оповещение = Новый ОписаниеОповещения(
			"ЗапуститьПриложениеНаКлиентеПослеЗапускаПриложения", ЭтотОбъект, ВходящийКонтекст,
			"ЗапуститьПриложениеНаКлиентеПриОшибкеЗапускаПриложения", ЭтотОбъект);
	
	ПараметрыЗапуска = ФайловаяСистемаКлиент.ПараметрыЗапускаПрограммы();
	ПараметрыЗапуска.Оповещение = Оповещение;
	ПараметрыЗапуска.ТекущийКаталог = ТекущийКаталог;
	ПараметрыЗапуска.ДождатьсяЗавершения = ДождатьсяЗавершения;
	ПараметрыЗапуска.ВыполнитьСНаивысшимиПравами = Истина;
	
	ФайловаяСистемаКлиент.ЗапуститьПрограмму(СтрокаКоманды, ПараметрыЗапуска);
	
КонецПроцедуры

Процедура ЗапуститьПриложениеНаКлиентеПослеЗапускаПриложения(КодВозврата, ВходящийКонтекст) Экспорт
	
	Если ТипЗнч(ВходящийКонтекст.ОповещениеОЗавершении) = Тип("ОписаниеОповещения") Тогда
		РезультатВыполнения = Новый Структура;
		РезультатВыполнения.Вставить("Выполнено", Истина);
		РезультатВыполнения.Вставить("ОписаниеОшибки", "");
		
		ВыполнитьОбработкуОповещения(
			ВходящийКонтекст.ОповещениеОЗавершении,
			РезультатВыполнения);
	КонецЕсли;

КонецПроцедуры

Процедура ЗапуститьПриложениеНаКлиентеПриОшибкеЗапускаПриложения(ИнформацияОбОшибке, СтандартнаяОбработка, ВходящийКонтекст) Экспорт
	
	СтандартнаяОбработка = Ложь;
	
	ОписаниеОшибки = НСтр("ru = 'Не удалось открыть файл %1.
                           |Возможно файл уже открыт.'");
	ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ОписаниеОшибки, ВходящийКонтекст.СтрокаКоманды);
	ОбщегоНазначенияКлиент.СообщитьПользователю(ОписаниеОшибки);
	
	РезультатВыполнения = Новый Структура;
	РезультатВыполнения.Вставить("Выполнено", Ложь);
	РезультатВыполнения.Вставить("ОписаниеОшибки", ОписаниеОшибки);
	РезультатВыполнения.Вставить("ВходящийКонтекст", ВходящийКонтекст);
	
	ВыполнитьОбработкуОповещения(
			ВходящийКонтекст.ОповещениеОЗавершении,
			РезультатВыполнения);

КонецПроцедуры

#КонецОбласти

Процедура ПослеУстановкиКриптопровайдера(Результат, Контекст) Экспорт
	
	Контекст.Вставить("ЭтоПовторнаяПроверка", Истина);
	ПроверитьУстановкуПрограммКриптографии(Контекст.Форма, Контекст, Контекст.Оповещение);
	
КонецПроцедуры

#КонецОбласти

// Конец Локализация

#КонецОбласти

#КонецОбласти

Процедура ПоказатьРезультатПроверкиСертификата(Сертификат, Результат, ВладелецФормы,
	Заголовок = "", ОбъединятьРезультаты = "НеОбъединять", ОбработкаЗавершения = Неопределено) Экспорт
	
	СерверныеПараметры = Новый Структура;
	СерверныеПараметры.Вставить("ЗаголовокФормы", Заголовок);
	СерверныеПараметры.Вставить("ПроверкаПриВыборе");
	СерверныеПараметры.Вставить("ПараметрыДополнительныхПроверок");
	СерверныеПараметры.Вставить("Сертификат", Сертификат);
	СерверныеПараметры.Вставить("РезультатПроверки", Результат);
	СерверныеПараметры.Вставить("ОбъединятьРезультаты", ОбъединятьРезультаты);
	
	ФормаПередачаПараметров().ОткрытьНовуюФорму("ПроверкаСертификата",
		СерверныеПараметры, Новый Структура, ОбработкаЗавершения, ВладелецФормы);
	
КонецПроцедуры

Процедура ОбработатьНавигационнуюСсылкуКлассификатора(Элемент, НавигационнаяСсылкаФорматированнойСтроки, СтандартнаяОбработка, ДополнительныеДанные = Неопределено) Экспорт
	
	СтандартнаяОбработка = Ложь;
	
	Параметры = ДополнительныеДанныеДляКлассификатораОшибок();
	Если ТипЗнч(ДополнительныеДанные) = Тип("Структура") Тогда
		ЗаполнитьЗначенияСвойств(Параметры, ДополнительныеДанные);
	КонецЕсли;
	
	Если НавигационнаяСсылкаФорматированнойСтроки = "ОткрытьСертификат" Тогда
		Если ЗначениеЗаполнено(Параметры.Сертификат)
			И ТипЗнч(Параметры.Сертификат) = Тип("СправочникСсылка.СертификатыКлючейЭлектроннойПодписиИШифрования") Тогда
			ПоказатьЗначение( , Параметры.Сертификат);
		ИначеЕсли ЗначениеЗаполнено(Параметры.ДанныеСертификата) Тогда
			ПараметрыФормы = Новый Структура;
			ПараметрыФормы.Вставить("АдресСертификата", Параметры.ДанныеСертификата);
			ОткрытьФорму("ОбщаяФорма.Сертификат", ПараметрыФормы);
		КонецЕсли;
	ИначеЕсли НавигационнаяСсылкаФорматированнойСтроки = "ОткрытьСписокПрограмм" Тогда
		
		ЭлектроннаяПодписьКлиент.ОткрытьНастройкиЭлектроннойПодписиИШифрования("Программы");
		
	ИначеЕсли НавигационнаяСсылкаФорматированнойСтроки = "ПодатьЗаявлениеНаСертификат" Тогда
		
		Если ЗначениеЗаполнено(Параметры.Сертификат) И ТипЗнч(Параметры.Сертификат) = Тип("СправочникСсылка.СертификатыКлючейЭлектроннойПодписиИШифрования") Тогда
			ПараметрыСоздания = Новый Структура;
			ПараметрыСоздания.Вставить("СоздатьЗаявление", Истина);
			ПараметрыСоздания.Вставить("СертификатОснование", Параметры.Сертификат);
			ДобавитьСертификат(ПараметрыСоздания);
		КонецЕсли;
	
	// Локализация
	
	ИначеЕсли НавигационнаяСсылкаФорматированнойСтроки = "ДобавитьУдостоверяющийЦентрВСписокРазрешенныхНеаккредитованных" Тогда
		
		Если ЗначениеЗаполнено(Параметры.Сертификат) И ЭлектроннаяПодписьКлиент.ОбщиеНастройки().ДоступнаПроверкаПоСпискуУЦ Тогда
			ПараметрыСоздания = Новый Структура;
			ПараметрыСоздания.Вставить("Сертификат", Параметры.Сертификат);
			ОткрытьФорму("ОбщаяФорма.РазрешенныеНеаккредитованныеУЦ", ПараметрыСоздания, Элемент);
		КонецЕсли;
	// Конец Локализация
		
	ИначеЕсли НавигационнаяСсылкаФорматированнойСтроки = "УстановитьСписокОтзываСертификата" Тогда
		
		Если ЗначениеЗаполнено(Параметры.ДанныеСертификата) Тогда
			ПараметрыУстановкиСпискаОтзыва = ПараметрыУстановкиСпискаОтзыва(Параметры.ДанныеСертификата);
			УстановитьСписокОтзываСертификата(ПараметрыУстановкиСпискаОтзыва);
		КонецЕсли;
	
	ИначеЕсли НавигационнаяСсылкаФорматированнойСтроки = "УстановитьКорневойСертификат" Тогда
		
		Если ЗначениеЗаполнено(Параметры.ДанныеСертификата) Тогда
			ЭлектроннаяПодписьКлиент.УстановитьКорневойСертификат(Параметры.ДанныеСертификата);
		КонецЕсли;
	
	ИначеЕсли НавигационнаяСсылкаФорматированнойСтроки = "УстановитьСертификат" Тогда
		
		Если ЗначениеЗаполнено(Параметры.ДанныеСертификата) Тогда
			ПараметрыУстановкиСертификата = ПараметрыУстановкиСертификата(Параметры.ДанныеСертификата);
			УстановитьСертификат(ПараметрыУстановкиСертификата);
		КонецЕсли;
		
	ИначеЕсли НавигационнаяСсылкаФорматированнойСтроки = "УстановитьСертификатВКонтейнер" Тогда
		
		Если ЗначениеЗаполнено(Параметры.ДанныеСертификата) Тогда
			ПараметрыУстановкиСертификата = ПараметрыУстановкиСертификата(Параметры.ДанныеСертификата);
			ПараметрыУстановкиСертификата.ВариантыУстановки = "Контейнер";
			УстановитьСертификат(ПараметрыУстановкиСертификата);
		КонецЕсли;
	
	ИначеЕсли НавигационнаяСсылкаФорматированнойСтроки = "УстановитьКомпоненту" Тогда
		
		Оповещение = Новый ОписаниеОповещения("ОповеститьОбУспешномПодключенииКомпоненты", ЭтотОбъект);
		ВыполнитьПослеПроверкиРасширенияИКомпоненты(Оповещение);
		
	ИначеЕсли СтрНайти(НавигационнаяСсылкаФорматированнойСтроки, "http") Тогда
		ФайловаяСистемаКлиент.ОткрытьНавигационнуюСсылку(НавигационнаяСсылкаФорматированнойСтроки, );
	ИначеЕсли СтрНачинаетсяС(НавигационнаяСсылкаФорматированнойСтроки, "e1cib") Тогда 
		СтандартнаяОбработка = Истина;
	Иначе
		ПоказатьПредупреждение(, НСтр("ru = 'Действие будет доступно в следующих обновлениях программы'"));
	КонецЕсли;
	
КонецПроцедуры

// Дополнительные данные для классификатора ошибок.
// 
// Возвращаемое значение:
//  Структура - дополнительные данные для классификатора ошибок:
//   * Сертификат - СправочникСсылка.СертификатыКлючейЭлектроннойПодписиИШифрования
//   * ДанныеСертификата - Строка
//   * ДополнительныеДанныеПроверокНаКлиенте - Структура
//   * ДополнительныеДанныеПроверокНаСервере - Структура
//
Функция ДополнительныеДанныеДляКлассификатораОшибок() Экспорт
	
	ДополнительныеДанные = Новый Структура;
	ДополнительныеДанные.Вставить("Сертификат");
	ДополнительныеДанные.Вставить("ДанныеСертификата");
	ДополнительныеДанные.Вставить("ПараметрыПодключенияКомпоненты");
	ДополнительныеДанные.Вставить("ДополнительныеДанныеПроверокНаКлиенте");
	ДополнительныеДанные.Вставить("ДополнительныеДанныеПроверокНаСервере");
	Возврат ДополнительныеДанные;
	
КонецФункции

// Используется для управления напоминаниями пользователя из формы сертификата, заявления на сертификат 
// и формы ОповещениеОбОкончанииСрокаДействия.
//
Процедура ИзменитьОтметкуОНапоминании(Сертификат, Напомнить, ФормаВладелец) Экспорт
	
	Если ФормаВладелец.ИмяФормы = "Обработка.ЗаявлениеНаВыпускНовогоКвалифицированногоСертификата.Форма.Форма" Тогда
		ИдентификаторНапоминания = "АвтоматическоеНапоминаниеОбИзмененииСостоянияЗаявления";
	Иначе	
		ИдентификаторНапоминания = "АвтоматическоеНапоминаниеОПродленииСертификата";
	КонецЕсли;	
	
	ЭлектроннаяПодписьСлужебныйВызовСервера.ИзменитьОтметкуОНапоминании(Сертификат, Напомнить, ИдентификаторНапоминания);
	
КонецПроцедуры

// Только для внутреннего использования
// Заполнение реквизита ФизическоеЛицо значением, найденным по наименованию из поля сертификата КомуВыдан
//
// Параметры:
//   Форма - ФормаКлиентскогоПриложения
//   КомуВыдан - Строка
//   ФизическоеЛицо - ОпределяемыйТип.ФизическоеЛицо - реквизит для заполнения физического лица
//
Процедура ПодобратьФизическоеЛицоДляСертификата(Форма, КомуВыдан, ФизическоеЛицо) Экспорт

	Если ЗначениеЗаполнено(ФизическоеЛицо) Тогда

		ТекстВопроса = НСтр("ru = 'Поле ""Физическое лицо"" заполнено. Перезаполнить?'");
		Параметры = Новый Структура("Форма, КомуВыдан, ФизическоеЛицо", Форма, КомуВыдан, ФизическоеЛицо);
		ОповещениеОтвет = Новый ОписаниеОповещения("ОтветПодобратьФизическоеЛицо", ЭтотОбъект, Параметры);

		ПоказатьВопрос(ОповещениеОтвет, ТекстВопроса,
			РежимДиалогаВопрос.ДаНет, , КодВозвратаДиалога.Да);
		Возврат;
	КонецЕсли;
	
	УстановитьФизическоеЛицо(Форма, КомуВыдан, ФизическоеЛицо);

КонецПроцедуры

Процедура ОтветПодобратьФизическоеЛицо(Результат, Параметры) Экспорт
	
	Если Результат = КодВозвратаДиалога.Да Тогда
		УстановитьФизическоеЛицо(Параметры.Форма, Параметры.КомуВыдан, Параметры.ФизическоеЛицо);
	КонецЕсли;
	
КонецПроцедуры

Процедура УстановитьФизическоеЛицо(Форма, КомуВыдан, ФизическоеЛицо)
	
	Форма.Модифицированность = Истина;
	
	КомуВыдан = ЭлектроннаяПодписьСлужебныйКлиентСервер.ПреобразоватьКомуВыданКВидуФИО(КомуВыдан);
	
	Результат = ЭлектроннаяПодписьСлужебныйВызовСервера.ПолучитьФизическиеЛицаПоПолюСертификатаКомуВыдан(КомуВыдан);
	
	Если НЕ Результат.Свойство("ФизическиеЛица") Тогда
		Возврат;
	КонецЕсли;
	
	ФизическиеЛица = Результат.ФизическиеЛица.Получить(КомуВыдан);
	
	ФизическоеЛицоПустаяСсылка = Новый (ТипЗнч(ФизическоеЛицо)); 
	ЭтоФормаЭлемента = ?(Форма.Элементы.Найти("СертификатФизическоеЛицо") = Неопределено, Истина, Ложь);
	
	Если ЭтоФормаЭлемента Тогда
		Форма.Объект.ФизическоеЛицо = ФизическоеЛицоПустаяСсылка;
	Иначе
		Форма.СертификатФизическоеЛицо = ФизическоеЛицоПустаяСсылка;
	КонецЕсли;
	
	Если ФизическиеЛица = Неопределено Тогда
		ОбработкаВыбора = Новый ОписаниеОповещения("ПриЗакрытииФормыВыбораФизическогоЛица", Форма);
		ПараметрыФормы = Новый Структура;
		ПараметрыФормы.Вставить("РежимВыбора", Истина);
		ОткрытьФорму(Результат.ПутьФормыВыбораФизическогоЛица, ПараметрыФормы, Форма, , , , ОбработкаВыбора,
			РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);	
		Возврат;
	КонецЕсли;
	
	Если ФизическиеЛица.Количество() = 1 Тогда
		Если ЭтоФормаЭлемента Тогда
			Форма.Объект.ФизическоеЛицо = ФизическиеЛица[0];
		Иначе
			Форма.СертификатФизическоеЛицо = ФизическиеЛица[0];
		КонецЕсли;
		Возврат;
	КонецЕсли;
	
	ФиксированныеНастройки = Новый НастройкиКомпоновкиДанных;

	Отбор = ФиксированныеНастройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
	Отбор.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Ссылка");
	Отбор.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
	Отбор.ПравоеЗначение = ФизическиеЛица;
	Отбор.Использование = Истина;

	ПараметрыФормы = Новый Структура;
	ПараметрыФормы.Вставить("ФиксированныеНастройки", ФиксированныеНастройки);
	ПараметрыФормы.Вставить("ОтборПоСсылке", Истина);
	ПараметрыФормы.Вставить("РежимВыбора", Истина);

	ОбработкаВыбора = Новый ОписаниеОповещения("ПриЗакрытииФормыВыбораФизическогоЛица", Форма);
	ОткрытьФорму(Результат.ПутьФормыВыбораФизическогоЛица, ПараметрыФормы, Форма, , , , ОбработкаВыбора,
		РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);	

КонецПроцедуры

// Прочитать свойства подписи.
// 
// Параметры:
//  ОповещениеОЗавершении - ОписаниеОповещения - возвращает структуру или массив структур
//  Подпись - ДвоичныеДанные
//          - Строка - адрес двоичных данных во временном хранилище
//          - Массив из Строка
//          - Массив из ДвоичныеДанные
//  ПрочитатьСертификаты - Булево - прочитать сертификаты подписи
//  ИспользоватьМенеджерКриптографии - Булево - использовать менеджер криптографии
//
Процедура ПрочитатьСвойстваПодписи(ОповещениеОЗавершении, Подпись, ПрочитатьСертификаты = Истина, ИспользоватьМенеджерКриптографии = Истина) Экспорт
	
	Если ТипЗнч(Подпись) = Тип("Строка") Или ТипЗнч(Подпись) = Тип("ДвоичныеДанные") Тогда
		ВернутьСтруктуру = Истина;
		МассивПодписей = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Подпись);
	Иначе
		ВернутьСтруктуру = Ложь;
		МассивПодписей = Подпись;
	КонецЕсли;
	
	Контекст = Новый Структура;
	Контекст.Вставить("Оповещение", ОповещениеОЗавершении);
	Контекст.Вставить("МассивПодписей", МассивПодписей);
	Контекст.Вставить("ОбработанныеПодписи", Новый Соответствие);
	Контекст.Вставить("ВернутьСтруктуру", ВернутьСтруктуру);
	
	Контекст.Вставить("ОбработанныеНаСервереПодписи");
	Контекст.Вставить("ПрочитатьСертификаты", ПрочитатьСертификаты);
	Контекст.Вставить("ИспользоватьМенеджерКриптографии", ИспользоватьМенеджерКриптографии);

	ПрочитатьСвойстваПодписейЦикл(Неопределено, Контекст);
	
КонецПроцедуры

Асинх Процедура ПрочитатьСвойстваПодписейЦикл(Результат, Контекст) Экспорт

	Если Контекст.ИспользоватьМенеджерКриптографии Тогда
		Если Контекст.МассивПодписей.Количество() > 0 Тогда
			
			Контекст.Вставить("Подпись", Контекст.МассивПодписей[0]);
			
			Если Контекст.ОбработанныеНаСервереПодписи <> Неопределено Тогда
				Результат = Контекст.ОбработанныеНаСервереПодписи.Получить(Контекст.Подпись);
				Если Результат.Успех <> Неопределено Тогда
					ДобавитьРезультатЧтенияПодписи(Результат, Контекст);
					Возврат;
				КонецЕсли;
			КонецЕсли;
			
			Оповещение = Новый ОписаниеОповещения("ПрочитатьСвойстваПодписиПослеСозданияМенеджераКриптографии", ЭтотОбъект, Контекст);
			ПараметрыСозданияМенеджераКриптографии = ПараметрыСозданияМенеджераКриптографии();
			ПараметрыСозданияМенеджераКриптографии.Программа = Контекст.Подпись;
			ПараметрыСозданияМенеджераКриптографии.ПоказатьОшибку = Ложь;
			СоздатьМенеджерКриптографии(Оповещение, "ЧтениеПодписи", ПараметрыСозданияМенеджераКриптографии);
			Возврат;
		Иначе
			РезультатЧтенияПодписей(Контекст);
		КонецЕсли;
	Иначе
		Соответствие = Новый Соответствие;
		Для Каждого Подпись Из Контекст.МассивПодписей Цикл
			СвойстваПодписиИзДвоичныхДанных = Ждать СвойстваПодписиИзДвоичныхДанных(Подпись, Контекст.ПрочитатьСертификаты);
			Соответствие.Вставить(Подпись, СвойстваПодписиИзДвоичныхДанных);
		КонецЦикла;
		Контекст.ОбработанныеПодписи = Соответствие;
		РезультатЧтенияПодписей(Контекст);
	КонецЕсли;

КонецПроцедуры

Процедура РезультатЧтенияПодписей(Контекст)
	
	Если Контекст.ВернутьСтруктуру Тогда
		Для Каждого КлючИЗначение Из Контекст.ОбработанныеПодписи Цикл
			Результат = КлючИЗначение.Значение;
			Прервать;
		КонецЦикла;
	Иначе
		Результат = Контекст.ОбработанныеПодписи;
	КонецЕсли;
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
	
КонецПроцедуры

Процедура ДобавитьРезультатЧтенияПодписи(Результат, Контекст)
	
	Контекст.ОбработанныеПодписи.Вставить(Контекст.Подпись, Результат);
	Контекст.МассивПодписей.Удалить(0);
	Оповещение = Новый ОписаниеОповещения("ПрочитатьСвойстваПодписейЦикл", ЭтотОбъект, Контекст);
	ВыполнитьОбработкуОповещения(Оповещение, Неопределено);

КонецПроцедуры

Асинх Процедура ПрочитатьСвойстваПодписиПослеСозданияМенеджераКриптографии(МенеджерКриптографии, Контекст) Экспорт
	
	Результат = ЭлектроннаяПодписьСлужебныйКлиентСервер.РезультатЧтенияСвойствПодписи();
	
	Если МенеджерКриптографии <> Неопределено Тогда
		Если ТипЗнч(МенеджерКриптографии) = Тип("Строка") Тогда
			Результат.ТекстОшибки = МенеджерКриптографии;
		Иначе
			Результат = Ждать СвойстваПодписиЧтениеМенеджеромКриптографии(
				Контекст.Подпись, МенеджерКриптографии, Контекст.ПрочитатьСертификаты);
			Если Результат.Успех = Истина Тогда
				ДобавитьРезультатЧтенияПодписи(Результат, Контекст);
				Возврат;
			Иначе
				Результат.Успех = Неопределено;
			КонецЕсли;
		КонецЕсли;
	ИначеЕсли Контекст.ИспользоватьМенеджерКриптографии И Контекст.ОбработанныеНаСервереПодписи = Неопределено
		И (ЭлектроннаяПодписьКлиент.ПроверятьЭлектронныеПодписиНаСервере()
		Или ЭлектроннаяПодписьКлиент.СоздаватьЭлектронныеПодписиНаСервере()) Тогда
		
		Контекст.ОбработанныеНаСервереПодписи = Новый Соответствие;
		Адрес = ПоместитьВоВременноеХранилище(Контекст.МассивПодписей);
		РезультатЧтенияНаСервере = ЭлектроннаяПодписьСлужебныйВызовСервера.СвойстваПодписи(
			Адрес, Контекст.ПрочитатьСертификаты);
		Контекст.ОбработанныеНаСервереПодписи = ПолучитьИзВременногоХранилища(РезультатЧтенияНаСервере);
		
		ДобавитьРезультатЧтенияПодписи(Контекст.ОбработанныеНаСервереПодписи.Получить(Контекст.Подпись), Контекст);
		Возврат;
	КонецЕсли;
	
	Если Контекст.ОбработанныеНаСервереПодписи <> Неопределено Тогда
		ДобавитьРезультатЧтенияПодписи(Контекст.ОбработанныеНаСервереПодписи.Получить(Контекст.Подпись), Контекст);
		Возврат;
	КонецЕсли;
	
	СвойстваПодписиИзДвоичныхДанных = Ждать СвойстваПодписиИзДвоичныхДанных(
		Контекст.Подпись, Контекст.ПрочитатьСертификаты);
	ЗаполнитьЗначенияСвойств(Результат, СвойстваПодписиИзДвоичныхДанных,, "Успех, ТекстОшибки");
	
	Если СвойстваПодписиИзДвоичныхДанных.Успех = Ложь Тогда
		Результат.Успех = Ложь;
		Результат.ТекстОшибки = ?(ПустаяСтрока(Результат.ТекстОшибки), "", Результат.ТекстОшибки + Символы.ПС)
			+ СвойстваПодписиИзДвоичныхДанных.ТекстОшибки;
	КонецЕсли;
	
	ДобавитьРезультатЧтенияПодписи(Результат, Контекст);
	
КонецПроцедуры

Асинх Функция СвойстваПодписиЧтениеМенеджеромКриптографии(Подпись, МенеджерКриптографии, ПрочитатьСертификаты)
	
	Результат = ЭлектроннаяПодписьСлужебныйКлиентСервер.РезультатЧтенияСвойствПодписи();
	
	ДвоичныеДанные = ЭлектроннаяПодписьСлужебныйКлиентСервер.ДвоичныеДанныеИзДанных(Подпись,
		"ЭлектроннаяПодписьСлужебныйКлиентСервер.СвойстваПодписиИзДвоичныхДанных");
	
	Попытка
		КонтейнерПодписи = Ждать МенеджерКриптографии.ПолучитьКонтейнерПодписейКриптографииАсинх(ДвоичныеДанные);
	Исключение
		Результат.Успех = Ложь;
		Результат.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru='При чтении данных подписи: %1'"), ОбработкаОшибок.КраткоеПредставлениеОшибки(
					ИнформацияОбОшибке()));
		Возврат Результат;
	КонецПопытки;

	ПараметрыПодписиКриптографии = Ждать ПараметрыПодписиКриптографии(
		КонтейнерПодписи, ДобавкаВремени(), ОбщегоНазначенияКлиент.ДатаСеанса());

	Результат.ТипПодписи = ПараметрыПодписиКриптографии.ТипПодписи;
	Результат.СрокДействияПоследнейМеткиВремени = ПараметрыПодписиКриптографии.СрокДействияПоследнейМеткиВремени;
	Результат.НеподтвержденнаяДатаПодписи = ПараметрыПодписиКриптографии.НеподтвержденнаяДатаПодписи;
	Результат.ДатаПодписиИзМетки = ПараметрыПодписиКриптографии.ДатаПодписиИзМетки;
	
	Если ПараметрыПодписиКриптографии.ОписаниеСертификата <> Неопределено Тогда
		Результат.Отпечаток = ПараметрыПодписиКриптографии.ОписаниеСертификата.Отпечаток;
		Результат.КомуВыданСертификат = ПараметрыПодписиКриптографии.ОписаниеСертификата.КомуВыдан;
	КонецЕсли;

	Если ПрочитатьСертификаты Тогда
		СтрокаПодписи = КонтейнерПодписи.Подписи[0];
		Если ЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатСуществует( 
						СтрокаПодписи.СертификатПодписи) Тогда
			Результат.Сертификат = Ждать СтрокаПодписи.СертификатПодписи.ВыгрузитьАсинх();
		КонецЕсли;
		Для Каждого Сертификат Из СтрокаПодписи.СертификатыПроверкиПодписи Цикл
			Если ЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатСуществует(Сертификат) Тогда
				Результат.Сертификаты.Добавить(Ждать Сертификат.ВыгрузитьАсинх());
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;

	Результат.Успех = Истина;
	Возврат Результат;
	
КонецФункции

Асинх Функция СвойстваПодписиИзДвоичныхДанных(Подпись, ПрочитатьСертификаты)
	
	Результат = ЭлектроннаяПодписьСлужебныйКлиентСервер.РезультатЧтенияСвойствПодписи();
	
	Попытка
		СвойстваПодписиИзДвоичныхДанных = ЭлектроннаяПодписьСлужебныйКлиентСервер.СвойстваПодписиИзДвоичныхДанных(
			Подпись, ДобавкаВремени(), ПрочитатьСертификаты);
		Если Не ЗначениеЗаполнено(СвойстваПодписиИзДвоичныхДанных.ТипПодписи) Тогда
			Результат.ТекстОшибки = НСтр("ru = 'Данные не являются подписью'");
			Результат.Успех = Ложь;
			Возврат Результат;
		КонецЕсли;
	Исключение
		Результат.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось прочитать свойства подписи: %1'"), ОбработкаОшибок.КраткоеПредставлениеОшибки(
			ИнформацияОбОшибке()));
		Результат.Успех = Ложь;
		Возврат Результат;
	КонецПопытки;

	Результат.ТипПодписи = СвойстваПодписиИзДвоичныхДанных.ТипПодписи;

	Если ЗначениеЗаполнено(СвойстваПодписиИзДвоичныхДанных.ДатаПодписания) Тогда
		Результат.НеподтвержденнаяДатаПодписи = СвойстваПодписиИзДвоичныхДанных.ДатаПодписания;
	КонецЕсли;
	Если ЗначениеЗаполнено(СвойстваПодписиИзДвоичныхДанных.ДатаШтампаВремени) Тогда
		Результат.ДатаПодписиИзМетки = СвойстваПодписиИзДвоичныхДанных.ДатаШтампаВремени;
	КонецЕсли;

	Если СвойстваПодписиИзДвоичныхДанных.Сертификаты.Количество() > 0 Тогда
		
		Если СвойстваПодписиИзДвоичныхДанных.Сертификаты.Количество() > 1 Тогда
			Попытка
				Результат.Сертификаты = Ждать СертификатыПоПорядкуДоКорневого(
					СвойстваПодписиИзДвоичныхДанных.Сертификаты);
				Результат.Сертификат = Результат.Сертификаты[0];
			Исключение
				Результат.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Не удалось прочитать свойства сертификатов: %1'"),
					ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
			КонецПопытки;
		Иначе
			Результат.Сертификат = СвойстваПодписиИзДвоичныхДанных.Сертификаты[0];
		КонецЕсли;
		
		Попытка
			Сертификат = Новый СертификатКриптографии();
			Ждать Сертификат.ИнициализироватьАсинх(Результат.Сертификат);
			Результат.Сертификат = Ждать Сертификат.ВыгрузитьАсинх();
			СвойстваСертификата = Ждать СвойстваСертификата(Сертификат);
			Результат.Отпечаток = СвойстваСертификата.Отпечаток;
			Результат.КомуВыданСертификат = СвойстваСертификата.КомуВыдан;
		Исключение
			Результат.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Не удалось прочитать свойства сертификата: %1'"),
				ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
		КонецПопытки;

	КонецЕсли;

	Результат.Успех = ПустаяСтрока(Результат.ТекстОшибки);
	
	Возврат Результат;

КонецФункции

// Для процедуры ПроверитьПодпись.
// 
// Параметры:
//  Результат  - см. ЭлектроннаяПодписьКлиентСервер.РезультатПроверкиПодписи.Результат. 
//  РезультатСтруктура - Неопределено
//                     - см. ЭлектроннаяПодписьКлиентСервер.РезультатПроверкиПодписи
//  ТребуетсяПроверка  - Неопределено, Булево - Истина, если удалось определить, что 
//                       подпись не удалось проверить из-за внешних обстоятельств. 
//
// Возвращаемое значение:
//   см. ЭлектроннаяПодписьКлиентСервер.РезультатПроверкиПодписи
//   см. ЭлектроннаяПодписьКлиентСервер.РезультатПроверкиПодписи.Результат - если Контекст.РезультатПроверки = Неопределено
//
Функция РезультатПроверкиПодписи(Результат, РезультатСтруктура = Неопределено, ТребуетсяПроверка = Неопределено)
	
	Если РезультатСтруктура = Неопределено Тогда
		Возврат Результат;
	Иначе
		
		РезультатСтруктура.Результат = Результат;
		
		Если Результат = Истина Тогда
			РезультатСтруктура.ПодписьВерна = Истина;
			РезультатСтруктура.ТребуетсяПроверка = Ложь;
			Возврат РезультатСтруктура;
		КонецЕсли;
		
		Если ТребуетсяПроверка <> Неопределено Тогда
			РезультатСтруктура.ТребуетсяПроверка = ТребуетсяПроверка;
		КонецЕсли;
		
		Если РезультатСтруктура.ТребуетсяПроверка = Ложь Тогда
			РезультатСтруктура.ПодписьВерна = Ложь;
		КонецЕсли;
		
		Возврат РезультатСтруктура;
	КонецЕсли;
	
КонецФункции

// Только для внутреннего использования.
// 
// Параметры:
//  ДанныеСертификатов - Массив из ДвоичныеДанные
// 
// Возвращаемое значение:
//  Массив из ДвоичныеДанные - сертификаты по порядку до корневого
//
Асинх Функция СертификатыПоПорядкуДоКорневого(ДанныеСертификатов) Экспорт
	
	ПоПорядку = Новый Массив;
	ОписаниеСертификатов = Новый Соответствие;
	СертификатыПоСубъектам = Новый Соответствие;
	
	Для Каждого ДанныеСертификата Из ДанныеСертификатов Цикл
		Сертификат = Новый СертификатКриптографии;
		Ждать Сертификат.ИнициализироватьАсинх(ДанныеСертификата);
		ПоПорядку.Добавить(ДанныеСертификата);
		ОписаниеСертификатов.Вставить(Сертификат, ДанныеСертификата);
		СертификатыПоСубъектам.Вставить(
			ЭлектроннаяПодписьСлужебныйКлиентСервер.КлючИздателя(Сертификат.Субъект),
			ДанныеСертификата);
	КонецЦикла;
	
	Для Счетчик = 1 По ПоПорядку.Количество() Цикл
		ЕстьИзменения = Ложь;
		ЭлектроннаяПодписьСлужебныйКлиентСервер.УпорядочитьСертификаты(
			ПоПорядку, ОписаниеСертификатов, СертификатыПоСубъектам, ЕстьИзменения); 
		Если Не ЕстьИзменения Тогда
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Возврат ПоПорядку;
	
КонецФункции

// Только для внутреннего использования.
// 
// Параметры:
//  КонтейнерПодписи - КонтейнерПодписейКриптографии
//  ДобавкаВремени - Число
//  ДатаСеанса - Дата
// 
// Возвращаемое значение:
//  Структура - параметры подписи криптографии:
//   * ТипПодписи          - ПеречислениеСсылка.ТипыПодписиКриптографии
//   * СрокДействияПоследнейМеткиВремени - Дата, Неопределено - заполняется только с помощью менеджера криптографии.
//   * ДатаПодписиИзМетки - Дата, Неопределено - самый ранний штамп времени.
//   * НеподтвержденнаяДатаПодписи - Дата - неподтвержденная дата подписи.
//                                 - Неопределено - неподтвержденная дата подписи отсутствует в данных подписи.
//   * ДатаПоследнейМеткиВремени - Дата - дата последней метки времени.
//   * Сертификат   - СертификатКриптографии - сертификат подписанта.
//   * ОписаниеСертификата - см. ЭлектроннаяПодписьКлиент.СвойстваСертификата.
//
Асинх Функция ПараметрыПодписиКриптографии(КонтейнерПодписи, ДобавкаВремени, ДатаСеанса) Экспорт

	ПараметрыПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.НовыеПараметрыПодписиКриптографии();
		
	Подпись = КонтейнерПодписи.Подписи[0];
	
	СертификатСуществует = ЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатСуществует(Подпись.СертификатПодписи);
	
	Если СертификатСуществует Тогда
		ПараметрыПодписи.ОписаниеСертификата = Ждать СвойстваСертификата(Подпись.СертификатПодписи);
	КонецЕсли;
	
	Возврат ЭлектроннаяПодписьСлужебныйКлиентСервер.ПараметрыПодписиКриптографии(ПараметрыПодписи, Подпись, СертификатСуществует, ДобавкаВремени, ДатаСеанса);
	
КонецФункции

#КонецОбласти

